update shapelib to 1.4.1 (#274)
authortsteven4 <tsteven4@users.noreply.github.com>
Sat, 24 Nov 2018 18:59:45 +0000 (11:59 -0700)
committerGitHub <noreply@github.com>
Sat, 24 Nov 2018 18:59:45 +0000 (11:59 -0700)
shapelib/COPYING [new file with mode: 0644]
shapelib/README.GPSBabel
shapelib/dbf_api.html
shapelib/dbfopen.c
shapelib/safileio.c
shapelib/shapefil.h
shapelib/shapelib.html
shapelib/shpopen.c

diff --git a/shapelib/COPYING b/shapelib/COPYING
new file mode 100644 (file)
index 0000000..0b643ac
--- /dev/null
@@ -0,0 +1,483 @@
+
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+                    675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
index 5597a0fc7198f2493b1601d54878c29993cd2da5..73ead7014f3a4a127b6b6126812337cdcfcebc8d 100644 (file)
@@ -1,8 +1,6 @@
-This is a subset of Shapelib v1.3.0 from http://shapelib.maptools.org/
+This is a subset of Shapelib v1.4.1 from http://shapelib.maptools.org/
 
-The source is largely unmodified.  It's subsetted here only to reduce 
+The source is unmodified.  It's subsetted here only to reduce 
 the amount of size in our tree that it takes and to reduce ongoing 
 merge maintenance.
 
-shpopen.c: int32_t instead of int32 was used to eliminate clang warnings.
-shpopen.c: include <stdint.h> for MSVC.
index f7a311bb3a14ecbf56863f625f7d29fa4e42eb1d..0bd0da1b84decb32de162adc192a1858949fb5e5 100644 (file)
@@ -175,9 +175,7 @@ int DBFAddField( DBFHandle hDBF, const char * pszFieldName,
 </pre>
 
   The DBFAddField() function is used to add new fields to an existing xBase
-  file opened with DBFOpen(), or created with DBFCreate().  Note that fields
-  can only be added to xBase files with no records, though this is limitation
-  of this API, not of the file format.<p>
+  file opened with DBFOpen(), or created with DBFCreate().<p>
 
   The DBFAddField() return value is the field number of the new field, or
   -1 if the addition of the field failed.<p>
index 1f717d3d1edd003cdccb4864aac8c4b6b046ca50..148e593a4eb626e933757456675bfe6e32c4219c 100644 (file)
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: dbfopen.c,v 1.89 2011-07-24 05:59:25 fwarmerdam Exp $
+ * $Id: dbfopen.c,v 1.92 2016-12-05 18:44:08 erouault Exp $
  *
  * Project:  Shapelib
  * Purpose:  Implementation of .dbf access API documented in dbf_api.html.
@@ -7,13 +7,14 @@
  *
  ******************************************************************************
  * Copyright (c) 1999, Frank Warmerdam
+ * Copyright (c) 2012-2013, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * This software is available under the following "MIT Style" license,
- * or at the option of the licensee under the LGPL (see LICENSE.LGPL).  This
+ * or at the option of the licensee under the LGPL (see COPYING).  This
  * option is discussed in more detail in shapelib.html.
  *
  * --
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
  ******************************************************************************
  *
  * $Log: dbfopen.c,v $
+ * Revision 1.92  2016-12-05 18:44:08  erouault
+ * * dbfopen.c, shapefil.h: write DBF end-of-file character 0x1A by default.
+ * This behaviour can be controlled with the DBFSetWriteEndOfFileChar()
+ * function.
+ *
+ * Revision 1.91  2016-12-05 12:44:05  erouault
+ * * Major overhaul of Makefile build system to use autoconf/automake.
+ *
+ * * Warning fixes in contrib/
+ *
+ * Revision 1.90  2016-12-04 15:30:15  erouault
+ * * shpopen.c, dbfopen.c, shptree.c, shapefil.h: resync with
+ * GDAL Shapefile driver. Mostly cleanups. SHPObject and DBFInfo
+ * structures extended with new members. New functions:
+ * DBFSetLastModifiedDate, SHPOpenLLEx, SHPRestoreSHX,
+ * SHPSetFastModeReadObject
+ *
+ * * sbnsearch.c: new file to implement original ESRI .sbn spatial
+ * index reading. (no write support). New functions:
+ * SBNOpenDiskTree, SBNCloseDiskTree, SBNSearchDiskTree,
+ * SBNSearchDiskTreeInteger, SBNSearchFreeIds
+ *
+ * * Makefile, makefile.vc, CMakeLists.txt, shapelib.def: updates
+ * with new file and symbols.
+ *
+ * * commit: helper script to cvs commit
+ *
  * Revision 1.89  2011-07-24 05:59:25  fwarmerdam
  * minimize use of CPLError in favor of SAHooks.Error()
  *
  *
  * Revision 1.77  2007/12/15 20:25:21  bram
  * dbfopen.c now reads the Code Page information from the DBF file, and exports
- * this information as a string through the DBFGetCodePage function.  This is 
- * either the number from the LDID header field ("LDID/<number>") or as the 
+ * this information as a string through the DBFGetCodePage function.  This is
+ * either the number from the LDID header field ("LDID/<number>") or as the
  * content of an accompanying .CPG file.  When creating a DBF file, the code can
  * be set using DBFCreateEx.
  *
 #include <ctype.h>
 #include <string.h>
 
-SHP_CVSID("$Id: dbfopen.c,v 1.89 2011-07-24 05:59:25 fwarmerdam Exp $")
+#ifdef USE_CPL
+#include "cpl_string.h"
+#else
+
+#if defined(_MSC_VER)
+# if _MSC_VER < 1900
+#     define snprintf _snprintf
+# endif
+#elif defined(WIN32) || defined(_WIN32)
+#  ifndef snprintf
+#     define snprintf _snprintf
+#  endif
+#endif
+
+#define CPLsprintf sprintf
+#define CPLsnprintf snprintf
+#endif
+
+SHP_CVSID("$Id: dbfopen.c,v 1.92 2016-12-05 18:44:08 erouault Exp $")
 
 #ifndef FALSE
 #  define FALSE                0
 #  define TRUE         1
 #endif
 
+/* File header size */
+#define XBASE_FILEHDR_SZ         32
+
+#define HEADER_RECORD_TERMINATOR 0x0D
+
+/* See http://www.manmrk.net/tutorials/database/xbase/dbf.html */
+#define END_OF_FILE_CHARACTER    0x1A
+
+#ifdef USE_CPL
+CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused) {}
+#else
+#define CPL_IGNORE_RET_VAL_INT(x) x
+#endif
+
 /************************************************************************/
 /*                             SfRealloc()                              */
 /*                                                                      */
@@ -198,8 +258,7 @@ static void * SfRealloc( void * pMem, int nNewSize )
 static void DBFWriteHeader(DBFHandle psDBF)
 
 {
-    unsigned char      abyHeader[XBASE_FLDHDR_SZ];
-    int                i;
+    unsigned char      abyHeader[XBASE_FILEHDR_SZ] = { 0 };
 
     if( !psDBF->bNoHeader )
         return;
@@ -209,21 +268,18 @@ static void DBFWriteHeader(DBFHandle psDBF)
 /* -------------------------------------------------------------------- */
 /*     Initialize the file header information.                         */
 /* -------------------------------------------------------------------- */
-    for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
-        abyHeader[i] = 0;
-
     abyHeader[0] = 0x03;               /* memo field? - just copying   */
 
-    /* write out a dummy date */
-    abyHeader[1] = 95;                 /* YY */
-    abyHeader[2] = 7;                  /* MM */
-    abyHeader[3] = 26;                 /* DD */
+    /* write out update date */
+    abyHeader[1] = (unsigned char) psDBF->nUpdateYearSince1900;
+    abyHeader[2] = (unsigned char) psDBF->nUpdateMonth;
+    abyHeader[3] = (unsigned char) psDBF->nUpdateDay;
 
     /* record count preset at zero */
 
     abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
     abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
-    
+
     abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
     abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
 
@@ -234,20 +290,31 @@ static void DBFWriteHeader(DBFHandle psDBF)
 /*      descriptions.                                                  */
 /* -------------------------------------------------------------------- */
     psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
-    psDBF->sHooks.FWrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
-    psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, 
+    psDBF->sHooks.FWrite( abyHeader, XBASE_FILEHDR_SZ, 1, psDBF->fp );
+    psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields,
                           psDBF->fp );
 
 /* -------------------------------------------------------------------- */
 /*      Write out the newline character if there is room for it.        */
 /* -------------------------------------------------------------------- */
-    if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
+    if( psDBF->nHeaderLength > XBASE_FLDHDR_SZ*psDBF->nFields +
+                               XBASE_FLDHDR_SZ )
     {
         char   cNewline;
 
-        cNewline = 0x0d;
+        cNewline = HEADER_RECORD_TERMINATOR;
         psDBF->sHooks.FWrite( &cNewline, 1, 1, psDBF->fp );
     }
+
+/* -------------------------------------------------------------------- */
+/*      If the file is new, add a EOF character.                        */
+/* -------------------------------------------------------------------- */
+    if( psDBF->nRecords == 0 && psDBF->bWriteEndOfFileChar )
+    {
+        char ch = END_OF_FILE_CHARACTER;
+
+        psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
+    }
 }
 
 /************************************************************************/
@@ -265,21 +332,30 @@ static int DBFFlushRecord( DBFHandle psDBF )
     {
        psDBF->bCurrentRecordModified = FALSE;
 
-       nRecordOffset = 
-            psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord 
+       nRecordOffset =
+            psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord
             + psDBF->nHeaderLength;
 
-       if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0 
-            || psDBF->sHooks.FWrite( psDBF->pszCurrentRecord, 
-                                     psDBF->nRecordLength, 
+       if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0
+            || psDBF->sHooks.FWrite( psDBF->pszCurrentRecord,
+                                     psDBF->nRecordLength,
                                      1, psDBF->fp ) != 1 )
         {
             char szMessage[128];
-            sprintf( szMessage, "Failure writing DBF record %d.", 
+            snprintf( szMessage, sizeof(szMessage), "Failure writing DBF record %d.",
                      psDBF->nCurrentRecord );
             psDBF->sHooks.Error( szMessage );
             return FALSE;
         }
+
+        if( psDBF->nCurrentRecord == psDBF->nRecords - 1 )
+        {
+            if( psDBF->bWriteEndOfFileChar )
+            {
+                char ch = END_OF_FILE_CHARACTER;
+                psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
+            }
+        }
     }
 
     return TRUE;
@@ -299,23 +375,23 @@ static int DBFLoadRecord( DBFHandle psDBF, int iRecord )
        if( !DBFFlushRecord( psDBF ) )
             return FALSE;
 
-       nRecordOffset = 
+       nRecordOffset =
             psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
 
        if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, SEEK_SET ) != 0 )
         {
             char szMessage[128];
-            sprintf( szMessage, "fseek(%ld) failed on DBF file.\n",
+            snprintf( szMessage, sizeof(szMessage), "fseek(%ld) failed on DBF file.",
                      (long) nRecordOffset );
             psDBF->sHooks.Error( szMessage );
             return FALSE;
         }
 
-       if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord, 
+       if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord,
                                  psDBF->nRecordLength, 1, psDBF->fp ) != 1 )
         {
             char szMessage[128];
-            sprintf( szMessage, "fread(%d) failed on DBF file.\n",
+            snprintf( szMessage, sizeof(szMessage), "fread(%d) failed on DBF file.",
                      psDBF->nRecordLength );
             psDBF->sHooks.Error( szMessage );
             return FALSE;
@@ -335,33 +411,49 @@ void SHPAPI_CALL
 DBFUpdateHeader( DBFHandle psDBF )
 
 {
-    unsigned char              abyFileHeader[32];
+    unsigned char              abyFileHeader[XBASE_FILEHDR_SZ];
 
     if( psDBF->bNoHeader )
         DBFWriteHeader( psDBF );
 
-    DBFFlushRecord( psDBF );
+    if( !DBFFlushRecord( psDBF ) )
+        return;
 
     psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
-    psDBF->sHooks.FRead( abyFileHeader, 32, 1, psDBF->fp );
-    
+    psDBF->sHooks.FRead( abyFileHeader, sizeof(abyFileHeader), 1, psDBF->fp );
+
+    abyFileHeader[1] = (unsigned char) psDBF->nUpdateYearSince1900;
+    abyFileHeader[2] = (unsigned char) psDBF->nUpdateMonth;
+    abyFileHeader[3] = (unsigned char) psDBF->nUpdateDay;
     abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
     abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
     abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
     abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);
-    
+
     psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
-    psDBF->sHooks.FWrite( abyFileHeader, 32, 1, psDBF->fp );
+    psDBF->sHooks.FWrite( abyFileHeader, sizeof(abyFileHeader), 1, psDBF->fp );
 
     psDBF->sHooks.FFlush( psDBF->fp );
 }
 
+/************************************************************************/
+/*                       DBFSetLastModifiedDate()                       */
+/************************************************************************/
+
+void SHPAPI_CALL
+DBFSetLastModifiedDate( DBFHandle psDBF, int nYYSince1900, int nMM, int nDD )
+{
+    psDBF->nUpdateYearSince1900 = nYYSince1900;
+    psDBF->nUpdateMonth = nMM;
+    psDBF->nUpdateDay = nDD;
+}
+
 /************************************************************************/
 /*                              DBFOpen()                               */
 /*                                                                      */
 /*      Open a .dbf file.                                               */
 /************************************************************************/
-   
+
 DBFHandle SHPAPI_CALL
 DBFOpen( const char * pszFilename, const char * pszAccess )
 
@@ -378,7 +470,7 @@ DBFOpen( const char * pszFilename, const char * pszAccess )
 /*                                                                      */
 /*      Open a .dbf file.                                               */
 /************************************************************************/
-   
+
 DBFHandle SHPAPI_CALL
 DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
 
@@ -389,18 +481,19 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
     int                        nFields, nHeadLen, iField, i;
     char               *pszBasename, *pszFullname;
     int                 nBufSize = 500;
+    size_t              nFullnameLen;
 
 /* -------------------------------------------------------------------- */
 /*      We only allow the access strings "rb" and "r+".                  */
 /* -------------------------------------------------------------------- */
-    if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0 
+    if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0
         && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
         && strcmp(pszAccess,"r+b") != 0 )
         return( NULL );
 
     if( strcmp(pszAccess,"r") == 0 )
         pszAccess = "rb";
+
     if( strcmp(pszAccess,"r+") == 0 )
         pszAccess = "rb+";
 
@@ -410,7 +503,7 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
 /* -------------------------------------------------------------------- */
     pszBasename = (char *) malloc(strlen(pszFilename)+5);
     strcpy( pszBasename, pszFilename );
-    for( i = strlen(pszBasename)-1; 
+    for( i = (int)strlen(pszBasename)-1;
         i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
               && pszBasename[i] != '\\';
         i-- ) {}
@@ -418,30 +511,31 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
     if( pszBasename[i] == '.' )
         pszBasename[i] = '\0';
 
-    pszFullname = (char *) malloc(strlen(pszBasename) + 5);
-    sprintf( pszFullname, "%s.dbf", pszBasename );
-        
+    nFullnameLen = strlen(pszBasename) + 5;
+    pszFullname = (char *) malloc(nFullnameLen);
+    snprintf( pszFullname, nFullnameLen, "%s.dbf", pszBasename );
+
     psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
     psDBF->fp = psHooks->FOpen( pszFullname, pszAccess );
     memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
 
     if( psDBF->fp == NULL )
     {
-        sprintf( pszFullname, "%s.DBF", pszBasename );
+        snprintf( pszFullname, nFullnameLen, "%s.DBF", pszBasename );
         psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess );
     }
 
-    sprintf( pszFullname, "%s.cpg", pszBasename );
+    snprintf( pszFullname, nFullnameLen, "%s.cpg", pszBasename );
     pfCPG = psHooks->FOpen( pszFullname, "r" );
     if( pfCPG == NULL )
     {
-        sprintf( pszFullname, "%s.CPG", pszBasename );
+        snprintf( pszFullname, nFullnameLen, "%s.CPG", pszBasename );
         pfCPG = psHooks->FOpen( pszFullname, "r" );
     }
 
     free( pszBasename );
     free( pszFullname );
-    
+
     if( psDBF->fp == NULL )
     {
         free( psDBF );
@@ -457,7 +551,7 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
 /*  Read Table Header info                                              */
 /* -------------------------------------------------------------------- */
     pabyBuf = (unsigned char *) malloc(nBufSize);
-    if( psDBF->sHooks.FRead( pabyBuf, 32, 1, psDBF->fp ) != 1 )
+    if( psDBF->sHooks.FRead( pabyBuf, XBASE_FILEHDR_SZ, 1, psDBF->fp ) != 1 )
     {
         psDBF->sHooks.FClose( psDBF->fp );
         if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
@@ -466,14 +560,16 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
         return NULL;
     }
 
-    psDBF->nRecords = 
-     pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
+    DBFSetLastModifiedDate(psDBF, pabyBuf[1], pabyBuf[2], pabyBuf[3]);
+
+    psDBF->nRecords =
+     pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + (pabyBuf[7] & 0x7f) *256*256*256;
 
     psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
     psDBF->nRecordLength = pabyBuf[10] + pabyBuf[11]*256;
     psDBF->iLanguageDriver = pabyBuf[29];
 
-    if (nHeadLen < 32)
+    if (psDBF->nRecordLength == 0 || nHeadLen < XBASE_FILEHDR_SZ)
     {
         psDBF->sHooks.FClose( psDBF->fp );
         if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
@@ -482,7 +578,7 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
         return NULL;
     }
 
-    psDBF->nFields = nFields = (nHeadLen - 32) / 32;
+    psDBF->nFields = nFields = (nHeadLen - XBASE_FILEHDR_SZ) / XBASE_FLDHDR_SZ;
 
     psDBF->pszCurrentRecord = (char *) malloc(psDBF->nRecordLength);
 
@@ -507,7 +603,7 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
     }
     if( psDBF->pszCodePage == NULL && pabyBuf[29] != 0 )
     {
-        sprintf( (char *) pabyBuf, "LDID/%d", psDBF->iLanguageDriver );
+        snprintf( (char *) pabyBuf, nBufSize, "LDID/%d", psDBF->iLanguageDriver );
         psDBF->pszCodePage = (char *) malloc(strlen((char*)pabyBuf) + 1);
         strcpy( psDBF->pszCodePage, (char *) pabyBuf );
     }
@@ -515,12 +611,13 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
 /* -------------------------------------------------------------------- */
 /*  Read in Field Definitions                                           */
 /* -------------------------------------------------------------------- */
-    
+
     pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
     psDBF->pszHeader = (char *) pabyBuf;
 
-    psDBF->sHooks.FSeek( psDBF->fp, 32, 0 );
-    if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
+    psDBF->sHooks.FSeek( psDBF->fp, XBASE_FILEHDR_SZ, 0 );
+    if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-XBASE_FILEHDR_SZ, 1,
+                             psDBF->fp ) != 1 )
     {
         psDBF->sHooks.FClose( psDBF->fp );
         free( pabyBuf );
@@ -538,7 +635,7 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
     {
        unsigned char           *pabyFInfo;
 
-       pabyFInfo = pabyBuf+iField*32;
+       pabyFInfo = pabyBuf+iField*XBASE_FLDHDR_SZ;
 
        if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
        {
@@ -564,10 +661,12 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
        if( iField == 0 )
            psDBF->panFieldOffset[iField] = 1;
        else
-           psDBF->panFieldOffset[iField] = 
+           psDBF->panFieldOffset[iField] =
              psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
     }
 
+    DBFSetWriteEndOfFileChar( psDBF, TRUE );
+
     return( psDBF );
 }
 
@@ -587,7 +686,7 @@ DBFClose(DBFHandle psDBF)
     if( psDBF->bNoHeader )
         DBFWriteHeader( psDBF );
 
-    DBFFlushRecord( psDBF );
+    CPL_IGNORE_RET_VAL_INT(DBFFlushRecord( psDBF ));
 
 /* -------------------------------------------------------------------- */
 /*      Update last access date, and number of records if we have      */
@@ -664,6 +763,7 @@ DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHook
     char       *pszFullname, *pszBasename;
     int                i, ldid = -1;
     char chZero = '\0';
+    size_t      nFullnameLen;
 
 /* -------------------------------------------------------------------- */
 /*     Compute the base (layer) name.  If there is any extension       */
@@ -671,7 +771,7 @@ DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHook
 /* -------------------------------------------------------------------- */
     pszBasename = (char *) malloc(strlen(pszFilename)+5);
     strcpy( pszBasename, pszFilename );
-    for( i = strlen(pszBasename)-1; 
+    for( i = (int)strlen(pszBasename)-1;
         i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
               && pszBasename[i] != '\\';
         i-- ) {}
@@ -679,31 +779,33 @@ DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHook
     if( pszBasename[i] == '.' )
         pszBasename[i] = '\0';
 
-    pszFullname = (char *) malloc(strlen(pszBasename) + 5);
-    sprintf( pszFullname, "%s.dbf", pszBasename );
+    nFullnameLen = strlen(pszBasename) + 5;
+    pszFullname = (char *) malloc(nFullnameLen);
+    snprintf( pszFullname, nFullnameLen, "%s.dbf", pszBasename );
 
 /* -------------------------------------------------------------------- */
 /*      Create the file.                                                */
 /* -------------------------------------------------------------------- */
     fp = psHooks->FOpen( pszFullname, "wb" );
-    if( fp == NULL ) {
-        free(pszBasename);
-        free(pszFullname);
+    if( fp == NULL )
+    {
+        free( pszBasename );
+        free( pszFullname );
         return( NULL );
     }
-    
+
     psHooks->FWrite( &chZero, 1, 1, fp );
     psHooks->FClose( fp );
 
     fp = psHooks->FOpen( pszFullname, "rb+" );
-    if( fp == NULL ) {
-        free(pszBasename);
-        free(pszFullname);
+    if( fp == NULL )
+    {
+        free( pszBasename );
+        free( pszFullname );
         return( NULL );
     }
 
-
-    sprintf( pszFullname, "%s.cpg", pszBasename );
+    snprintf( pszFullname, nFullnameLen, "%s.cpg", pszBasename );
     if( pszCodePage != NULL )
     {
         if( strncmp( pszCodePage, "LDID/", 5 ) == 0 )
@@ -737,8 +839,8 @@ DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHook
     psDBF->nRecords = 0;
     psDBF->nFields = 0;
     psDBF->nRecordLength = 1;
-    psDBF->nHeaderLength = 33;
-    
+    psDBF->nHeaderLength = XBASE_FILEHDR_SZ + 1; /* + 1 for HEADER_RECORD_TERMINATOR */
+
     psDBF->panFieldOffset = NULL;
     psDBF->panFieldSize = NULL;
     psDBF->panFieldDecimals = NULL;
@@ -758,6 +860,9 @@ DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHook
         psDBF->pszCodePage = (char * ) malloc( strlen(pszCodePage) + 1 );
         strcpy( psDBF->pszCodePage, pszCodePage );
     }
+    DBFSetLastModifiedDate(psDBF, 95, 7, 26); /* dummy date */
+
+    DBFSetWriteEndOfFileChar(psDBF, TRUE);
 
     return( psDBF );
 }
@@ -769,7 +874,7 @@ DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHook
 /************************************************************************/
 
 int SHPAPI_CALL
-DBFAddField(DBFHandle psDBF, const char * pszFieldName, 
+DBFAddField(DBFHandle psDBF, const char * pszFieldName,
             DBFFieldType eType, int nWidth, int nDecimals )
 
 {
@@ -782,7 +887,7 @@ DBFAddField(DBFHandle psDBF, const char * pszFieldName,
     else
         chNativeType = 'N';
 
-    return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType, 
+    return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType,
                                   nWidth, nDecimals );
 }
 
@@ -814,7 +919,7 @@ static char DBFGetNullCharacter(char chType)
 /************************************************************************/
 
 int SHPAPI_CALL
-DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName, 
+DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
                       char chType, int nWidth, int nDecimals )
 
 {
@@ -829,14 +934,36 @@ DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
     if( !DBFFlushRecord( psDBF ) )
         return -1;
 
+    if( psDBF->nHeaderLength + XBASE_FLDHDR_SZ > 65535 )
+    {
+        char szMessage[128];
+        snprintf( szMessage, sizeof(szMessage),
+                  "Cannot add field %s. Header length limit reached "
+                  "(max 65535 bytes, 2046 fields).",
+                  pszFieldName );
+        psDBF->sHooks.Error( szMessage );
+        return -1;
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Do some checking to ensure we can add records to this file.     */
 /* -------------------------------------------------------------------- */
     if( nWidth < 1 )
         return -1;
 
-    if( nWidth > 255 )
-        nWidth = 255;
+    if( nWidth > XBASE_FLD_MAX_WIDTH )
+        nWidth = XBASE_FLD_MAX_WIDTH;
+
+    if( psDBF->nRecordLength + nWidth > 65535 )
+    {
+        char szMessage[128];
+        snprintf( szMessage, sizeof(szMessage),
+                  "Cannot add field %s. Record length limit reached "
+                  "(max 65535 bytes).",
+                  pszFieldName );
+        psDBF->sHooks.Error( szMessage );
+        return -1;
+    }
 
     nOldRecordLength = psDBF->nRecordLength;
     nOldHeaderLength = psDBF->nHeaderLength;
@@ -847,16 +974,16 @@ DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
 /* -------------------------------------------------------------------- */
     psDBF->nFields++;
 
-    psDBF->panFieldOffset = (int *) 
+    psDBF->panFieldOffset = (int *)
         SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
 
-    psDBF->panFieldSize = (int *) 
+    psDBF->panFieldSize = (int *)
         SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
 
-    psDBF->panFieldDecimals = (int *) 
+    psDBF->panFieldDecimals = (int *)
         SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
 
-    psDBF->pachFieldType = (char *) 
+    psDBF->pachFieldType = (char *)
         SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
 
 /* -------------------------------------------------------------------- */
@@ -871,20 +998,18 @@ DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
 /* -------------------------------------------------------------------- */
 /*      Extend the required header information.                         */
 /* -------------------------------------------------------------------- */
-    psDBF->nHeaderLength += 32;
+    psDBF->nHeaderLength += XBASE_FLDHDR_SZ;
     psDBF->bUpdated = FALSE;
 
-    psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
+    psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,
+                                          psDBF->nFields*XBASE_FLDHDR_SZ);
 
-    pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
+    pszFInfo = psDBF->pszHeader + XBASE_FLDHDR_SZ * (psDBF->nFields-1);
 
-    for( i = 0; i < 32; i++ )
+    for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
         pszFInfo[i] = '\0';
 
-    if( (int) strlen(pszFieldName) < 10 )
-        strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
-    else
-        strncpy( pszFInfo, pszFieldName, 10);
+    strncpy( pszFInfo, pszFieldName, XBASE_FLDNAME_LEN_WRITE );
 
     pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
 
@@ -898,7 +1023,7 @@ DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
         pszFInfo[16] = (unsigned char) nWidth;
         pszFInfo[17] = (unsigned char) nDecimals;
     }
-    
+
 /* -------------------------------------------------------------------- */
 /*      Make the current record buffer appropriately larger.            */
 /* -------------------------------------------------------------------- */
@@ -936,6 +1061,17 @@ DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
         psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
     }
 
+    if( psDBF->bWriteEndOfFileChar )
+    {
+        char ch = END_OF_FILE_CHARACTER;
+
+        nRecordOffset =
+            psDBF->nRecordLength * (SAOffset) psDBF->nRecords + psDBF->nHeaderLength;
+
+        psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+        psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
+    }
+
     /* free record */
     free(pszRecord);
 
@@ -945,6 +1081,7 @@ DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
 
     psDBF->nCurrentRecord = -1;
     psDBF->bCurrentRecordModified = FALSE;
+    psDBF->bUpdated = TRUE;
 
     return( psDBF->nFields-1 );
 }
@@ -995,7 +1132,7 @@ static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
 /* -------------------------------------------------------------------- */
 /*     Extract the requested field.                                    */
 /* -------------------------------------------------------------------- */
-    strncpy( psDBF->pszWorkField,
+    memcpy( psDBF->pszWorkField,
             ((const char *) pabyRec) + psDBF->panFieldOffset[iField],
             psDBF->panFieldSize[iField] );
     psDBF->pszWorkField[psDBF->panFieldSize[iField]] = '\0';
@@ -1005,11 +1142,17 @@ static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
 /* -------------------------------------------------------------------- */
 /*      Decode the field.                                               */
 /* -------------------------------------------------------------------- */
-    if( chReqType == 'N' )
+    if( chReqType == 'I' )
     {
-        psDBF->dfDoubleField = psDBF->sHooks.Atof(psDBF->pszWorkField);
+        psDBF->fieldValue.nIntField = atoi(psDBF->pszWorkField);
 
-       pReturnField = &(psDBF->dfDoubleField);
+        pReturnField = &(psDBF->fieldValue.nIntField);
+    }
+    else if( chReqType == 'N' )
+    {
+        psDBF->fieldValue.dfDoubleField = psDBF->sHooks.Atof(psDBF->pszWorkField);
+
+        pReturnField = &(psDBF->fieldValue.dfDoubleField);
     }
 
 /* -------------------------------------------------------------------- */
@@ -1032,7 +1175,7 @@ static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
             *pchDst = '\0';
     }
 #endif
-    
+
     return( pReturnField );
 }
 
@@ -1046,14 +1189,14 @@ int SHPAPI_CALL
 DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
 
 {
-    double     *pdValue;
+    int        *pnValue;
 
-    pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
+    pnValue = (int *) DBFReadAttribute( psDBF, iRecord, iField, 'I' );
 
-    if( pdValue == NULL )
+    if( pnValue == NULL )
         return 0;
     else
-        return( (int) *pdValue );
+        return( *pnValue );
 }
 
 /************************************************************************/
@@ -1201,6 +1344,8 @@ DBFGetRecordCount( DBFHandle psDBF )
 /*                          DBFGetFieldInfo()                           */
 /*                                                                      */
 /*      Return any requested information about the field.               */
+/*      pszFieldName must be at least XBASE_FLDNAME_LEN_READ+1 (=12)    */
+/*      bytes long.                                                     */
 /************************************************************************/
 
 DBFFieldType SHPAPI_CALL
@@ -1221,20 +1366,21 @@ DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
     {
        int     i;
 
-       strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
-       pszFieldName[11] = '\0';
-       for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
+       strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*XBASE_FLDHDR_SZ,
+                 XBASE_FLDNAME_LEN_READ );
+       pszFieldName[XBASE_FLDNAME_LEN_READ] = '\0';
+       for( i = XBASE_FLDNAME_LEN_READ - 1; i > 0 && pszFieldName[i] == ' '; i-- )
            pszFieldName[i] = '\0';
     }
 
     if ( psDBF->pachFieldType[iField] == 'L' )
        return( FTLogical);
 
-    else if( psDBF->pachFieldType[iField] == 'N' 
+    else if( psDBF->pachFieldType[iField] == 'N'
              || psDBF->pachFieldType[iField] == 'F' )
     {
-       if( psDBF->panFieldDecimals[iField] > 0 
-            || psDBF->panFieldSize[iField] > 10 )
+       if( psDBF->panFieldDecimals[iField] > 0
+            || psDBF->panFieldSize[iField] >= 10 )
            return( FTDouble );
        else
            return( FTInteger );
@@ -1257,7 +1403,7 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
 {
     int                i, j, nRetResult = TRUE;
     unsigned char      *pabyRec;
-    char       szSField[400], szFormat[20];
+    char       szSField[XBASE_FLD_MAX_WIDTH+1], szFormat[20];
 
 /* -------------------------------------------------------------------- */
 /*     Is this a valid record?                                         */
@@ -1316,46 +1462,27 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
       case 'D':
       case 'N':
       case 'F':
-       if( psDBF->panFieldDecimals[iField] == 0 )
-       {
-            int                nWidth = psDBF->panFieldSize[iField];
+      {
+        int            nWidth = psDBF->panFieldSize[iField];
 
-            if( (int) sizeof(szSField)-2 < nWidth )
-                nWidth = sizeof(szSField)-2;
+        if( (int) sizeof(szSField)-2 < nWidth )
+            nWidth = sizeof(szSField)-2;
 
-           sprintf( szFormat, "%%%dd", nWidth );
-           sprintf(szSField, szFormat, (int) *((double *) pValue) );
-           if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
-            {
-               szSField[psDBF->panFieldSize[iField]] = '\0';
-                nRetResult = FALSE;
-            }
-
-           strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
-                   szSField, strlen(szSField) );
-       }
-       else
-       {
-            int                nWidth = psDBF->panFieldSize[iField];
-
-            if( (int) sizeof(szSField)-2 < nWidth )
-                nWidth = sizeof(szSField)-2;
-
-           sprintf( szFormat, "%%%d.%df", 
-                     nWidth, psDBF->panFieldDecimals[iField] );
-           sprintf(szSField, szFormat, *((double *) pValue) );
-           if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
-            {
-               szSField[psDBF->panFieldSize[iField]] = '\0';
-                nRetResult = FALSE;
-            }
-           strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
-                   szSField, strlen(szSField) );
-       }
-       break;
+        snprintf( szFormat, sizeof(szFormat), "%%%d.%df",
+                    nWidth, psDBF->panFieldDecimals[iField] );
+        CPLsnprintf(szSField, sizeof(szSField), szFormat, *((double *) pValue) );
+        if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
+        {
+            szSField[psDBF->panFieldSize[iField]] = '\0';
+            nRetResult = FALSE;
+        }
+        strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
+            szSField, strlen(szSField) );
+        break;
+      }
 
       case 'L':
-        if (psDBF->panFieldSize[iField] >= 1  && 
+        if (psDBF->panFieldSize[iField] >= 1  &&
             (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
             *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
         break;
@@ -1370,7 +1497,7 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
         {
             memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
                     psDBF->panFieldSize[iField] );
-           j = strlen((char *) pValue);
+           j = (int)strlen((char *) pValue);
         }
 
        strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
@@ -1439,7 +1566,7 @@ DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
     {
         memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
                 psDBF->panFieldSize[iField] );
-        j = strlen((char *) pValue);
+        j = (int)strlen((char *) pValue);
     }
 
     strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
@@ -1603,21 +1730,24 @@ DBFReadTuple(DBFHandle psDBF, int hEntity )
 /************************************************************************/
 
 DBFHandle SHPAPI_CALL
-DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ) 
+DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
 {
     DBFHandle  newDBF;
 
    newDBF = DBFCreateEx ( pszFilename, psDBF->pszCodePage );
-   if ( newDBF == NULL ) return ( NULL ); 
-   
+   if ( newDBF == NULL ) return ( NULL );
+
    newDBF->nFields = psDBF->nFields;
    newDBF->nRecordLength = psDBF->nRecordLength;
    newDBF->nHeaderLength = psDBF->nHeaderLength;
-    
-   newDBF->pszHeader = (char *) malloc ( newDBF->nHeaderLength );
-   memcpy ( newDBF->pszHeader, psDBF->pszHeader, newDBF->nHeaderLength );
-   
-   newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields ); 
+
+   if( psDBF->pszHeader )
+   {
+        newDBF->pszHeader = (char *) malloc ( XBASE_FLDHDR_SZ * psDBF->nFields );
+        memcpy ( newDBF->pszHeader, psDBF->pszHeader, XBASE_FLDHDR_SZ * psDBF->nFields );
+   }
+
+   newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
    memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
    newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
    memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
@@ -1628,11 +1758,13 @@ DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
 
    newDBF->bNoHeader = TRUE;
    newDBF->bUpdated = TRUE;
-   
+   newDBF->bWriteEndOfFileChar = psDBF->bWriteEndOfFileChar;
+
    DBFWriteHeader ( newDBF );
    DBFClose ( newDBF );
-   
+
    newDBF = DBFOpen ( pszFilename, "rb+" );
+   newDBF->bWriteEndOfFileChar = psDBF->bWriteEndOfFileChar;
 
    return ( newDBF );
 }
@@ -1665,9 +1797,9 @@ DBFGetNativeFieldType( DBFHandle psDBF, int iField )
 static void str_to_upper (char *string)
 {
     int len;
-    short i = -1;
+    int i = -1;
 
-    len = strlen (string);
+    len = (int)strlen (string);
 
     while (++i < len)
         if (isalpha(string[i]) && islower(string[i]))
@@ -1686,20 +1818,23 @@ int SHPAPI_CALL
 DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
 
 {
-    char          name[12], name1[12], name2[12];
+    char          name[XBASE_FLDNAME_LEN_READ+1],
+                  name1[XBASE_FLDNAME_LEN_READ+1],
+                  name2[XBASE_FLDNAME_LEN_READ+1];
     int           i;
 
-    strncpy(name1, pszFieldName,11);
-    name1[11] = '\0';
+    strncpy(name1, pszFieldName,XBASE_FLDNAME_LEN_READ);
+    name1[XBASE_FLDNAME_LEN_READ] = '\0';
     str_to_upper(name1);
 
     for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
     {
         DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
-        strncpy(name2,name,11);
+        strncpy(name2,name,XBASE_FLDNAME_LEN_READ);
+        name2[XBASE_FLDNAME_LEN_READ] = '\0';
         str_to_upper(name2);
 
-        if(!strncmp(name1,name2,10))
+        if(!strcmp(name1,name2))
             return(i);
     }
     return(-1);
@@ -1737,7 +1872,7 @@ int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape )
 /*                        DBFMarkRecordDeleted()                        */
 /************************************************************************/
 
-int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape, 
+int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
                                       int bIsDeleted )
 
 {
@@ -1761,7 +1896,7 @@ int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
 /* -------------------------------------------------------------------- */
     if( bIsDeleted )
         chNewFlag = '*';
-    else 
+    else
         chNewFlag = ' ';
 
     if( psDBF->pszCurrentRecord[0] != chNewFlag )
@@ -1826,28 +1961,29 @@ DBFDeleteField(DBFHandle psDBF, int iField)
     /* resize fields arrays */
     psDBF->nFields--;
 
-    psDBF->panFieldOffset = (int *) 
+    psDBF->panFieldOffset = (int *)
         SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
 
-    psDBF->panFieldSize = (int *) 
+    psDBF->panFieldSize = (int *)
         SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
 
-    psDBF->panFieldDecimals = (int *) 
+    psDBF->panFieldDecimals = (int *)
         SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
 
-    psDBF->pachFieldType = (char *) 
+    psDBF->pachFieldType = (char *)
         SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
 
     /* update header information */
-    psDBF->nHeaderLength -= 32;
+    psDBF->nHeaderLength -= XBASE_FLDHDR_SZ;
     psDBF->nRecordLength -= nDeletedFieldSize;
 
     /* overwrite field information in header */
-    memmove(psDBF->pszHeader + iField*32,
-           psDBF->pszHeader + (iField+1)*32,
-           sizeof(char) * (psDBF->nFields - iField)*32);
+    memmove(psDBF->pszHeader + iField*XBASE_FLDHDR_SZ,
+           psDBF->pszHeader + (iField+1)*XBASE_FLDHDR_SZ,
+           sizeof(char) * (psDBF->nFields - iField)*XBASE_FLDHDR_SZ);
 
-    psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
+    psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,
+                                          psDBF->nFields*XBASE_FLDHDR_SZ);
 
     /* update size of current record appropriately */
     psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
@@ -1867,14 +2003,14 @@ DBFDeleteField(DBFHandle psDBF, int iField)
     /* shift records to their new positions */
     for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
     {
-        nRecordOffset = 
+        nRecordOffset =
             nOldRecordLength * (SAOffset) iRecord + nOldHeaderLength;
 
         /* load record */
         psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
         psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
 
-        nRecordOffset = 
+        nRecordOffset =
             psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
 
         /* move record in two steps */
@@ -1886,6 +2022,12 @@ DBFDeleteField(DBFHandle psDBF, int iField)
 
     }
 
+    if( psDBF->bWriteEndOfFileChar )
+    {
+        char ch = END_OF_FILE_CHARACTER;
+        psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
+    }
+
     /* TODO: truncate file */
 
     /* free record */
@@ -1893,6 +2035,7 @@ DBFDeleteField(DBFHandle psDBF, int iField)
 
     psDBF->nCurrentRecord = -1;
     psDBF->bCurrentRecordModified = FALSE;
+    psDBF->bUpdated = TRUE;
 
     return TRUE;
 }
@@ -1927,11 +2070,13 @@ DBFReorderFields( DBFHandle psDBF, int* panMap )
     if( !DBFFlushRecord( psDBF ) )
         return FALSE;
 
-    panFieldOffsetNew = (int *) malloc(sizeof(int) * psDBF->nFields);
-    panFieldSizeNew = (int *) malloc(sizeof(int) *  psDBF->nFields);
-    panFieldDecimalsNew = (int *) malloc(sizeof(int) *  psDBF->nFields);
-    pachFieldTypeNew = (char *) malloc(sizeof(char) *  psDBF->nFields);
-    pszHeaderNew = (char*) malloc(sizeof(char) * 32 *  psDBF->nFields);
+    /* a simple malloc() would be enough, but calloc() helps clang static analyzer */
+    panFieldOffsetNew = (int *) calloc(sizeof(int), psDBF->nFields);
+    panFieldSizeNew = (int *) calloc(sizeof(int),  psDBF->nFields);
+    panFieldDecimalsNew = (int *) calloc(sizeof(int), psDBF->nFields);
+    pachFieldTypeNew = (char *) calloc(sizeof(char), psDBF->nFields);
+    pszHeaderNew = (char*) malloc(sizeof(char) * XBASE_FLDHDR_SZ * 
+                                  psDBF->nFields);
 
     /* shuffle fields definitions */
     for(i=0; i < psDBF->nFields; i++)
@@ -1939,8 +2084,8 @@ DBFReorderFields( DBFHandle psDBF, int* panMap )
         panFieldSizeNew[i] = psDBF->panFieldSize[panMap[i]];
         panFieldDecimalsNew[i] = psDBF->panFieldDecimals[panMap[i]];
         pachFieldTypeNew[i] = psDBF->pachFieldType[panMap[i]];
-        memcpy(pszHeaderNew + i * 32,
-               psDBF->pszHeader + panMap[i] * 32, 32);
+        memcpy(pszHeaderNew + i * XBASE_FLDHDR_SZ,
+               psDBF->pszHeader + panMap[i] * XBASE_FLDHDR_SZ, XBASE_FLDHDR_SZ);
     }
     panFieldOffsetNew[0] = 1;
     for(i=1; i < psDBF->nFields; i++)
@@ -2003,6 +2148,7 @@ DBFReorderFields( DBFHandle psDBF, int* panMap )
 
     psDBF->nCurrentRecord = -1;
     psDBF->bCurrentRecordModified = FALSE;
+    psDBF->bUpdated = TRUE;
 
     return TRUE;
 }
@@ -2023,7 +2169,7 @@ DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
     int   nOffset;
     int   nOldWidth;
     int   nOldRecordLength;
-    int   nRecordOffset;
+    SAOffset  nRecordOffset;
     char* pszFInfo;
     char  chOldType;
     int   bIsNULL;
@@ -2049,8 +2195,8 @@ DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
     if( nWidth < 1 )
         return -1;
 
-    if( nWidth > 255 )
-        nWidth = 255;
+    if( nWidth > XBASE_FLD_MAX_WIDTH )
+        nWidth = XBASE_FLD_MAX_WIDTH;
 
 /* -------------------------------------------------------------------- */
 /*      Assign the new field information fields.                        */
@@ -2062,15 +2208,12 @@ DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
 /* -------------------------------------------------------------------- */
 /*      Update the header information.                                  */
 /* -------------------------------------------------------------------- */
-    pszFInfo = psDBF->pszHeader + 32 * iField;
+    pszFInfo = psDBF->pszHeader + XBASE_FLDHDR_SZ * iField;
 
-    for( i = 0; i < 32; i++ )
+    for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
         pszFInfo[i] = '\0';
 
-    if( (int) strlen(pszFieldName) < 10 )
-        strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
-    else
-        strncpy( pszFInfo, pszFieldName, 10);
+    strncpy( pszFInfo, pszFieldName, XBASE_FLDNAME_LEN_WRITE );
 
     pszFInfo[11] = psDBF->pachFieldType[iField];
 
@@ -2111,6 +2254,7 @@ DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
         char* pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength);
         char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
 
+        /* cppcheck-suppress uninitdata */
         pszOldField[nOldWidth] = 0;
 
         /* move records to their new positions */
@@ -2157,6 +2301,18 @@ DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
             psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
         }
 
+        if( psDBF->bWriteEndOfFileChar )
+        {
+            char ch = END_OF_FILE_CHARACTER;
+
+            nRecordOffset =
+                psDBF->nRecordLength * (SAOffset) psDBF->nRecords + psDBF->nHeaderLength;
+
+            psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+            psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
+        }
+        /* TODO: truncate file */
+
         free(pszRecord);
         free(pszOldField);
     }
@@ -2165,6 +2321,7 @@ DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
         char* pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
         char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
 
+        /* cppcheck-suppress uninitdata */
         pszOldField[nOldWidth] = 0;
 
         /* move records to their new positions */
@@ -2216,12 +2373,33 @@ DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
             psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
         }
 
+        if( psDBF->bWriteEndOfFileChar )
+        {
+            char ch = END_OF_FILE_CHARACTER;
+
+            nRecordOffset =
+                psDBF->nRecordLength * (SAOffset) psDBF->nRecords + psDBF->nHeaderLength;
+
+            psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+            psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
+        }
+
         free(pszRecord);
         free(pszOldField);
     }
 
     psDBF->nCurrentRecord = -1;
     psDBF->bCurrentRecordModified = FALSE;
+    psDBF->bUpdated = TRUE;
 
     return TRUE;
 }
+
+/************************************************************************/
+/*                    DBFSetWriteEndOfFileChar()                        */
+/************************************************************************/
+
+void SHPAPI_CALL DBFSetWriteEndOfFileChar( DBFHandle psDBF, int bWriteFlag )
+{
+    psDBF->bWriteEndOfFileChar = bWriteFlag;
+}
index f3affe2ea504fb8d559d878544765120dd140dcb..533e7ada35b90f957bacf6c29c7ea62fcefcb664 100644 (file)
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: safileio.c,v 1.4 2008-01-16 20:05:14 bram Exp $
+ * $Id: safileio.c,v 1.5 2016-12-05 12:44:05 erouault Exp $
  *
  * Project:  Shapelib
  * Purpose:  Default implementation of file io based on stdio.
@@ -9,7 +9,7 @@
  * Copyright (c) 2007, Frank Warmerdam
  *
  * This software is available under the following "MIT Style" license,
- * or at the option of the licensee under the LGPL (see LICENSE.LGPL).  This
+ * or at the option of the licensee under the LGPL (see COPYING).  This
  * option is discussed in more detail in shapelib.html.
  *
  * --
  ******************************************************************************
  *
  * $Log: safileio.c,v $
+ * Revision 1.5  2016-12-05 12:44:05  erouault
+ * * Major overhaul of Makefile build system to use autoconf/automake.
+ *
+ * * Warning fixes in contrib/
+ *
  * Revision 1.4  2008-01-16 20:05:14  bram
  * Add file hooks that accept UTF-8 encoded filenames on some platforms.  Use SASetupUtf8Hooks
  *  tosetup the hooks and check SHPAPI_UTF8_HOOKS for its availability.  Currently, this
@@ -65,7 +70,7 @@
 #include <string.h>
 #include <stdio.h>
 
-SHP_CVSID("$Id: safileio.c,v 1.4 2008-01-16 20:05:14 bram Exp $");
+SHP_CVSID("$Id: safileio.c,v 1.5 2016-12-05 12:44:05 erouault Exp $");
 
 #ifdef SHPAPI_UTF8_HOOKS
 #   ifdef SHPAPI_WINDOWS
index e90b1cc9d2c5b0bd4fe82e2bf492d7954541e820..08c64599622193e0766925d1ee3db93eb0afa3e9 100644 (file)
@@ -2,7 +2,7 @@
 #define SHAPEFILE_H_INCLUDED
 
 /******************************************************************************
- * $Id: shapefil.h,v 1.52 2011-12-11 22:26:46 fwarmerdam Exp $
+ * $Id: shapefil.h,v 1.55 2016-12-05 18:44:08 erouault Exp $
  *
  * Project:  Shapelib
  * Purpose:  Primary include file for Shapelib.
  *
  ******************************************************************************
  * Copyright (c) 1999, Frank Warmerdam
+ * Copyright (c) 2012-2016, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * This software is available under the following "MIT Style" license,
- * or at the option of the licensee under the LGPL (see LICENSE.LGPL).  This
+ * or at the option of the licensee under the LGPL (see COPYING).  This
  * option is discussed in more detail in shapelib.html.
  *
  * --
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
  ******************************************************************************
  *
  * $Log: shapefil.h,v $
+ * Revision 1.55  2016-12-05 18:44:08  erouault
+ * * dbfopen.c, shapefil.h: write DBF end-of-file character 0x1A by default.
+ * This behaviour can be controlled with the DBFSetWriteEndOfFileChar()
+ * function.
+ *
+ * Revision 1.54  2016-12-05 12:44:05  erouault
+ * * Major overhaul of Makefile build system to use autoconf/automake.
+ *
+ * * Warning fixes in contrib/
+ *
+ * Revision 1.53  2016-12-04 15:30:15  erouault
+ * * shpopen.c, dbfopen.c, shptree.c, shapefil.h: resync with
+ * GDAL Shapefile driver. Mostly cleanups. SHPObject and DBFInfo
+ * structures extended with new members. New functions:
+ * DBFSetLastModifiedDate, SHPOpenLLEx, SHPRestoreSHX,
+ * SHPSetFastModeReadObject
+ *
+ * * sbnsearch.c: new file to implement original ESRI .sbn spatial
+ * index reading. (no write support). New functions:
+ * SBNOpenDiskTree, SBNCloseDiskTree, SBNSearchDiskTree,
+ * SBNSearchDiskTreeInteger, SBNSearchFreeIds
+ *
+ * * Makefile, makefile.vc, CMakeLists.txt, shapelib.def: updates
+ * with new file and symbols.
+ *
+ * * commit: helper script to cvs commit
+ *
  * Revision 1.52  2011-12-11 22:26:46  fwarmerdam
  * upgrade .qix access code to use SAHooks (gdal #3365)
  *
 #include <dbmalloc.h>
 #endif
 
+#ifdef USE_CPL
+#include "cpl_conv.h"
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -166,7 +198,7 @@ extern "C" {
 /*      is disabled.                                                    */
 /* -------------------------------------------------------------------- */
 #define DISABLE_MULTIPATCH_MEASURE
-    
+
 /* -------------------------------------------------------------------- */
 /*      SHPAPI_CALL                                                     */
 /*                                                                      */
@@ -190,7 +222,7 @@ extern "C" {
 /*        #define SHPAPI_CALL __declspec(dllexport) __stdcall           */
 /*        #define SHPAPI_CALL1 __declspec(dllexport) * __stdcall        */
 /*                                                                      */
-/*      The complexity of the situtation is partly caused by the        */
+/*      The complexity of the situation is partly caused by the        */
 /*      peculiar requirement of Visual C++ that __stdcall appear        */
 /*      after any "*"'s in the return value of a function while the     */
 /*      __declspec(dllexport) must appear before them.                  */
@@ -213,17 +245,17 @@ extern "C" {
 #ifndef SHPAPI_CALL1
 #  define SHPAPI_CALL1(x)      x SHPAPI_CALL
 #endif
-    
+
 /* -------------------------------------------------------------------- */
 /*      Macros for controlling CVSID and ensuring they don't appear     */
 /*      as unreferenced variables resulting in lots of warnings.        */
 /* -------------------------------------------------------------------- */
 #ifndef DISABLE_CVSID
 #  if defined(__GNUC__) && __GNUC__ >= 4
-#    define SHP_CVSID(string)     static char cpl_cvsid[] __attribute__((used)) = string;
+#    define SHP_CVSID(string)     static const char cpl_cvsid[] __attribute__((used)) = string;
 #  else
-#    define SHP_CVSID(string)     static char cpl_cvsid[] = string; \
-static char *cvsid_aw() { return( cvsid_aw() ? ((char *) NULL) : cpl_cvsid ); }
+#    define SHP_CVSID(string)     static const char cpl_cvsid[] = string; \
+static const char *cvsid_aw() { return( cvsid_aw() ? NULL : cpl_cvsid ); }
 #  endif
 #else
 #  define SHP_CVSID(string)
@@ -234,8 +266,8 @@ static char *cvsid_aw() { return( cvsid_aw() ? ((char *) NULL) : cpl_cvsid ); }
 /*      UTF-8 encoded filenames Unicode filenames                       */
 /* -------------------------------------------------------------------- */
 #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
-#      define SHPAPI_WINDOWS
-#      define SHPAPI_UTF8_HOOKS
+#  define SHPAPI_WINDOWS
+#  define SHPAPI_UTF8_HOOKS
 #endif
 
 /* -------------------------------------------------------------------- */
@@ -269,29 +301,36 @@ void SHPAPI_CALL SASetupUtf8Hooks( SAHooks *psHooks );
 /************************************************************************/
 /*                             SHP Support.                             */
 /************************************************************************/
-typedef        struct
+typedef struct tagSHPObject SHPObject;
+
+typedef struct
 {
     SAHooks sHooks;
 
     SAFile      fpSHP;
-    SAFile     fpSHX;
+    SAFile      fpSHX;
+
+    int         nShapeType;  /* SHPT_* */
 
-    int                nShapeType;                             /* SHPT_* */
-    
-    unsigned int       nFileSize;                              /* SHP file */
+    unsigned int nFileSize;  /* SHP file */
 
     int         nRecords;
-    int                nMaxRecords;
-    unsigned int               *panRecOffset;
-    unsigned int               *panRecSize;
+    int         nMaxRecords;
+    unsigned int*panRecOffset;
+    unsigned int *panRecSize;
 
-    double     adBoundsMin[4];
-    double     adBoundsMax[4];
+    double      adBoundsMin[4];
+    double      adBoundsMax[4];
 
-    int                bUpdated;
+    int         bUpdated;
 
     unsigned char *pabyRec;
     int         nBufSize;
+
+    int            bFastModeReadObject;
+    unsigned char *pabyObjectBuf;
+    int            nObjectBufSize;
+    SHPObject*     psCachedObject;
 } SHPInfo;
 
 typedef SHPInfo * SHPHandle;
@@ -299,66 +338,66 @@ typedef SHPInfo * SHPHandle;
 /* -------------------------------------------------------------------- */
 /*      Shape types (nSHPType)                                          */
 /* -------------------------------------------------------------------- */
-#define SHPT_NULL      0
-#define SHPT_POINT     1
-#define SHPT_ARC       3
-#define SHPT_POLYGON   5
-#define SHPT_MULTIPOINT        8
-#define SHPT_POINTZ    11
-#define SHPT_ARCZ      13
-#define SHPT_POLYGONZ  15
+#define SHPT_NULL       0
+#define SHPT_POINT      1
+#define SHPT_ARC        3
+#define SHPT_POLYGON    5
+#define SHPT_MULTIPOINT 8
+#define SHPT_POINTZ     11
+#define SHPT_ARCZ       13
+#define SHPT_POLYGONZ   15
 #define SHPT_MULTIPOINTZ 18
-#define SHPT_POINTM    21
-#define SHPT_ARCM      23
-#define SHPT_POLYGONM  25
+#define SHPT_POINTM     21
+#define SHPT_ARCM       23
+#define SHPT_POLYGONM   25
 #define SHPT_MULTIPOINTM 28
 #define SHPT_MULTIPATCH 31
 
-
 /* -------------------------------------------------------------------- */
 /*      Part types - everything but SHPT_MULTIPATCH just uses           */
 /*      SHPP_RING.                                                      */
 /* -------------------------------------------------------------------- */
 
-#define SHPP_TRISTRIP  0
-#define SHPP_TRIFAN    1
-#define SHPP_OUTERRING 2
-#define SHPP_INNERRING 3
-#define SHPP_FIRSTRING 4
-#define SHPP_RING      5
+#define SHPP_TRISTRIP   0
+#define SHPP_TRIFAN     1
+#define SHPP_OUTERRING  2
+#define SHPP_INNERRING  3
+#define SHPP_FIRSTRING  4
+#define SHPP_RING       5
 
 /* -------------------------------------------------------------------- */
 /*      SHPObject - represents on shape (without attributes) read       */
 /*      from the .shp file.                                             */
 /* -------------------------------------------------------------------- */
-typedef struct
+struct tagSHPObject
 {
-    int                nSHPType;
+    int    nSHPType;
+
+    int    nShapeId;  /* -1 is unknown/unassigned */
 
-    int                nShapeId; /* -1 is unknown/unassigned */
+    int    nParts;
+    int    *panPartStart;
+    int    *panPartType;
 
-    int                nParts;
-    int                *panPartStart;
-    int                *panPartType;
-    
-    int                nVertices;
-    double     *padfX;
-    double     *padfY;
-    double     *padfZ;
-    double     *padfM;
+    int    nVertices;
+    double *padfX;
+    double *padfY;
+    double *padfZ;
+    double *padfM;
 
-    double     dfXMin;
-    double     dfYMin;
-    double     dfZMin;
-    double     dfMMin;
+    double dfXMin;
+    double dfYMin;
+    double dfZMin;
+    double dfMMin;
 
-    double     dfXMax;
-    double     dfYMax;
-    double     dfZMax;
-    double     dfMMax;
+    double dfXMax;
+    double dfYMax;
+    double dfZMax;
+    double dfMMax;
 
-    int                bMeasureIsUsed;
-} SHPObject;
+    int    bMeasureIsUsed;
+    int    bFastModeReadObject;
+};
 
 /* -------------------------------------------------------------------- */
 /*      SHP API Prototypes                                              */
@@ -369,8 +408,22 @@ typedef struct
 SHPHandle SHPAPI_CALL
       SHPOpen( const char * pszShapeFile, const char * pszAccess );
 SHPHandle SHPAPI_CALL
-      SHPOpenLL( const char *pszShapeFile, const char *pszAccess, 
+      SHPOpenLL( const char *pszShapeFile, const char *pszAccess,
                  SAHooks *psHooks );
+SHPHandle SHPAPI_CALL
+      SHPOpenLLEx( const char *pszShapeFile, const char *pszAccess,
+                  SAHooks *psHooks, int bRestoreSHX );
+
+int SHPAPI_CALL
+      SHPRestoreSHX( const char *pszShapeFile, const char *pszAccess,
+                  SAHooks *psHooks );
+
+/* If setting bFastMode = TRUE, the content of SHPReadObject() is owned by the SHPHandle. */
+/* So you cannot have 2 valid instances of SHPReadObject() simultaneously. */
+/* The SHPObject padfZ and padfM members may be NULL depending on the geometry */
+/* type. It is illegal to free at hand any of the pointer members of the SHPObject structure */
+void SHPAPI_CALL SHPSetFastModeReadObject( SHPHandle hSHP, int bFastMode );
+
 SHPHandle SHPAPI_CALL
       SHPCreate( const char * pszShapeFile, int nShapeType );
 SHPHandle SHPAPI_CALL
@@ -390,15 +443,15 @@ void SHPAPI_CALL
 void SHPAPI_CALL
       SHPComputeExtents( SHPObject * psObject );
 SHPObject SHPAPI_CALL1(*)
-      SHPCreateObject( int nSHPType, int nShapeId, int nParts, 
+      SHPCreateObject( int nSHPType, int nShapeId, int nParts,
                        const int * panPartStart, const int * panPartType,
-                       int nVertices, 
+                       int nVertices,
                        const double * padfX, const double * padfY,
                        const double * padfZ, const double * padfM );
 SHPObject SHPAPI_CALL1(*)
       SHPCreateSimpleObject( int nSHPType, int nVertices,
-                             const double * padfX, 
-                             const double * padfY, 
+                             const double * padfX,
+                             const double * padfY,
                              const double * padfZ );
 
 int SHPAPI_CALL
@@ -417,7 +470,7 @@ const char SHPAPI_CALL1(*)
 /* -------------------------------------------------------------------- */
 
 /* this can be two or four for binary or quad tree */
-#define MAX_SUBNODE    4
+#define MAX_SUBNODE 4
 
 /* upper limit of tree levels for automatic estimation */
 #define MAX_DEFAULT_TREE_DEPTH 12
@@ -425,62 +478,61 @@ const char SHPAPI_CALL1(*)
 typedef struct shape_tree_node
 {
     /* region covered by this node */
-    double     adfBoundsMin[4];
-    double     adfBoundsMax[4];
+    double      adfBoundsMin[4];
+    double      adfBoundsMax[4];
 
     /* list of shapes stored at this node.  The papsShapeObj pointers
        or the whole list can be NULL */
-    int                nShapeCount;
-    int                *panShapeIds;
+    int         nShapeCount;
+    int         *panShapeIds;
     SHPObject   **papsShapeObj;
 
-    int                nSubNodes;
+    int         nSubNodes;
     struct shape_tree_node *apsSubNode[MAX_SUBNODE];
-    
+
 } SHPTreeNode;
 
 typedef struct
 {
     SHPHandle   hSHP;
-    
-    int                nMaxDepth;
-    int                nDimension;
+
+    int         nMaxDepth;
+    int         nDimension;
     int         nTotalCount;
-    
-    SHPTreeNode        *psRoot;
+
+    SHPTreeNode *psRoot;
 } SHPTree;
 
 SHPTree SHPAPI_CALL1(*)
       SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth,
                      double *padfBoundsMin, double *padfBoundsMax );
-void    SHPAPI_CALL
+void SHPAPI_CALL
       SHPDestroyTree( SHPTree * hTree );
 
-int    SHPAPI_CALL
+int SHPAPI_CALL
       SHPWriteTree( SHPTree *hTree, const char * pszFilename );
 
-int    SHPAPI_CALL
+int SHPAPI_CALL
       SHPTreeAddShapeId( SHPTree * hTree, SHPObject * psObject );
-int    SHPAPI_CALL
+int SHPAPI_CALL
       SHPTreeRemoveShapeId( SHPTree * hTree, int nShapeId );
 
-void   SHPAPI_CALL
+void SHPAPI_CALL
       SHPTreeTrimExtraNodes( SHPTree * hTree );
 
-int    SHPAPI_CALL1(*)
+int SHPAPI_CALL1(*)
       SHPTreeFindLikelyShapes( SHPTree * hTree,
                                double * padfBoundsMin,
                                double * padfBoundsMax,
                                int * );
-int     SHPAPI_CALL
+int SHPAPI_CALL
       SHPCheckBoundsOverlap( double *, double *, double *, double *, int );
 
-int SHPAPI_CALL1(*) 
-SHPSearchDiskTree( FILE *fp, 
+int SHPAPI_CALL1(*)
+SHPSearchDiskTree( FILE *fp,
                    double *padfBoundsMin, double *padfBoundsMax,
                    int *pnShapeCount );
 
-
 typedef struct SHPDiskTreeInfo* SHPTreeDiskHandle;
 
 SHPTreeDiskHandle SHPAPI_CALL
@@ -490,49 +542,86 @@ SHPTreeDiskHandle SHPAPI_CALL
 void SHPAPI_CALL
     SHPCloseDiskTree( SHPTreeDiskHandle hDiskTree );
 
-int SHPAPI_CALL1(*) 
-SHPSearchDiskTreeEx( SHPTreeDiskHandle hDiskTree, 
-                   double *padfBoundsMin, double *padfBoundsMax,
-                   int *pnShapeCount );
+int SHPAPI_CALL1(*)
+SHPSearchDiskTreeEx( SHPTreeDiskHandle hDiskTree,
+                     double *padfBoundsMin, double *padfBoundsMax,
+                     int *pnShapeCount );
 
 int SHPAPI_CALL
     SHPWriteTreeLL(SHPTree *hTree, const char *pszFilename, SAHooks *psHooks );
 
+/* -------------------------------------------------------------------- */
+/*      SBN Search API                                                  */
+/* -------------------------------------------------------------------- */
+
+typedef struct SBNSearchInfo* SBNSearchHandle;
+
+SBNSearchHandle SHPAPI_CALL
+    SBNOpenDiskTree( const char* pszSBNFilename,
+                 SAHooks *psHooks );
+
+void SHPAPI_CALL
+    SBNCloseDiskTree( SBNSearchHandle hSBN );
+
+int SHPAPI_CALL1(*)
+SBNSearchDiskTree( SBNSearchHandle hSBN,
+                   double *padfBoundsMin, double *padfBoundsMax,
+                   int *pnShapeCount );
+
+int SHPAPI_CALL1(*)
+SBNSearchDiskTreeInteger( SBNSearchHandle hSBN,
+                          int bMinX, int bMinY, int bMaxX, int bMaxY,
+                          int *pnShapeCount );
+
+void SHPAPI_CALL SBNSearchFreeIds( int* panShapeId );
+
 /************************************************************************/
 /*                             DBF Support.                             */
 /************************************************************************/
-typedef        struct
+typedef struct
 {
     SAHooks sHooks;
 
-    SAFile     fp;
+    SAFile      fp;
 
     int         nRecords;
 
-    int                nRecordLength;
-    int                nHeaderLength;
-    int                nFields;
-    int                *panFieldOffset;
-    int                *panFieldSize;
-    int                *panFieldDecimals;
-    char       *pachFieldType;
+    int         nRecordLength; /* Must fit on uint16 */
+    int         nHeaderLength; /* File header length (32) + field
+                                  descriptor length + spare space.
+                                  Must fit on uint16 */
+    int         nFields;
+    int         *panFieldOffset;
+    int         *panFieldSize;
+    int         *panFieldDecimals;
+    char        *pachFieldType;
 
-    char       *pszHeader;
+    char        *pszHeader; /* Field descriptors */
 
-    int                nCurrentRecord;
-    int                bCurrentRecordModified;
-    char       *pszCurrentRecord;
+    int         nCurrentRecord;
+    int         bCurrentRecordModified;
+    char        *pszCurrentRecord;
 
     int         nWorkFieldLength;
     char        *pszWorkField;
-    
-    int                bNoHeader;
-    int                bUpdated;
 
-    double      dfDoubleField;
+    int         bNoHeader;
+    int         bUpdated;
+
+    union
+    {
+        double      dfDoubleField;
+        int         nIntField;
+    } fieldValue;
 
     int         iLanguageDriver;
     char        *pszCodePage;
+
+    int         nUpdateYearSince1900; /* 0-255 */
+    int         nUpdateMonth; /* 1-12 */
+    int         nUpdateDay; /* 1-31 */
+
+    int         bWriteEndOfFileChar; /* defaults to TRUE */
 } DBFInfo;
 
 typedef DBFInfo * DBFHandle;
@@ -545,8 +634,14 @@ typedef enum {
   FTInvalid
 } DBFFieldType;
 
-#define XBASE_FLDHDR_SZ       32
-
+/* Field descriptor/header size */
+#define XBASE_FLDHDR_SZ         32
+/* Shapelib read up to 11 characters, even if only 10 should normally be used */
+#define XBASE_FLDNAME_LEN_READ  11
+/* On writing, we limit to 10 characters */
+#define XBASE_FLDNAME_LEN_WRITE 10
+/* Normally only 254 characters should be used. We tolerate 255 historically */
+#define XBASE_FLD_MAX_WIDTH     255
 
 DBFHandle SHPAPI_CALL
       DBFOpen( const char * pszDBFFile, const char * pszAccess );
@@ -560,19 +655,19 @@ DBFHandle SHPAPI_CALL
 DBFHandle SHPAPI_CALL
       DBFCreateLL( const char * pszDBFFile, const char * pszCodePage, SAHooks *psHooks );
 
-int    SHPAPI_CALL
+int SHPAPI_CALL
       DBFGetFieldCount( DBFHandle psDBF );
-int    SHPAPI_CALL
+int SHPAPI_CALL
       DBFGetRecordCount( DBFHandle psDBF );
-int    SHPAPI_CALL
+int SHPAPI_CALL
       DBFAddField( DBFHandle hDBF, const char * pszFieldName,
                    DBFFieldType eType, int nWidth, int nDecimals );
 
-int    SHPAPI_CALL
+int SHPAPI_CALL
       DBFAddNativeFieldType( DBFHandle hDBF, const char * pszFieldName,
                              char chType, int nWidth, int nDecimals );
 
-int    SHPAPI_CALL
+int SHPAPI_CALL
       DBFDeleteField( DBFHandle hDBF, int iField );
 
 int SHPAPI_CALL
@@ -583,25 +678,25 @@ int SHPAPI_CALL
                          char chType, int nWidth, int nDecimals );
 
 DBFFieldType SHPAPI_CALL
-      DBFGetFieldInfo( DBFHandle psDBF, int iField, 
+      DBFGetFieldInfo( DBFHandle psDBF, int iField,
                        char * pszFieldName, int * pnWidth, int * pnDecimals );
 
 int SHPAPI_CALL
       DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName);
 
-int    SHPAPI_CALL
+int SHPAPI_CALL
       DBFReadIntegerAttribute( DBFHandle hDBF, int iShape, int iField );
-double         SHPAPI_CALL
+double SHPAPI_CALL
       DBFReadDoubleAttribute( DBFHandle hDBF, int iShape, int iField );
 const char SHPAPI_CALL1(*)
       DBFReadStringAttribute( DBFHandle hDBF, int iShape, int iField );
 const char SHPAPI_CALL1(*)
       DBFReadLogicalAttribute( DBFHandle hDBF, int iShape, int iField );
-int     SHPAPI_CALL
+int SHPAPI_CALL
       DBFIsAttributeNULL( DBFHandle hDBF, int iShape, int iField );
 
 int SHPAPI_CALL
-      DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField, 
+      DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField,
                                 int nFieldValue );
 int SHPAPI_CALL
       DBFWriteDoubleAttribute( DBFHandle hDBF, int iShape, int iField,
@@ -614,7 +709,7 @@ int SHPAPI_CALL
 
 int SHPAPI_CALL
      DBFWriteLogicalAttribute( DBFHandle hDBF, int iShape, int iField,
-                              const char lFieldValue);
+                               const char lFieldValue);
 int SHPAPI_CALL
      DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
                                void * pValue );
@@ -624,22 +719,27 @@ int SHPAPI_CALL
       DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple );
 
 int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape );
-int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape, 
+int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
                                       int bIsDeleted );
 
 DBFHandle SHPAPI_CALL
       DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename );
-void   SHPAPI_CALL
+
+void SHPAPI_CALL
       DBFClose( DBFHandle hDBF );
 void    SHPAPI_CALL
       DBFUpdateHeader( DBFHandle hDBF );
-char    SHPAPI_CALL
+char SHPAPI_CALL
       DBFGetNativeFieldType( DBFHandle hDBF, int iField );
 
 const char SHPAPI_CALL1(*)
       DBFGetCodePage(DBFHandle psDBF );
 
+void SHPAPI_CALL
+    DBFSetLastModifiedDate( DBFHandle psDBF, int nYYSince1900, int nMM, int nDD );
+
+void SHPAPI_CALL DBFSetWriteEndOfFileChar( DBFHandle psDBF, int bWriteFlag );
+
 #ifdef __cplusplus
 }
 #endif
index 2015283c14d0208bab37f94b0a0057487fc15e12..19a433604c48c54bdd4cfe59e0e67d7a8c2a9286 100644 (file)
@@ -1,11 +1,11 @@
 <html>
 <head>
-<title>Shapefile C Library V1.2</title>
-<link href="http://www.maptools.org/maptools.css" rel="stylesheet" type="text/css">
+<title>Shapefile C Library</title>
+<link href="maptools.css" rel="stylesheet" type="text/css">
 </head>
 
 <body>
-<h1>Shapefile C Library V1.2</h1>
+<h1>Shapefile C Library</h1>
 
 <h2>Purpose</h2>
 
@@ -46,7 +46,7 @@ XXX.dbf - holds the attributes in xBase (dBase) format.
 <h2>Download</h2>
 
 Source code, and some other odds and ends can be downloaded from
-<a href="http://download.osgeo.org/shapelib">http://download.osgeo.org/shapelib</a> or <a href="http://shapelib.maptools.org/dl">http://shapelib.maptools.org/dl</a>.<p>
+<a href="http://download.osgeo.org/shapelib">http://download.osgeo.org/shapelib</a>.<p>
 
 Shapelib is available for anonymous CVS access:
 
@@ -230,6 +230,3 @@ MS Excel to calculate the area of polygons and export as shapefiles.<p>
 
 </body>
 </html>
-
-
-
index 480c1b8a443cab07cfcf4b829a5c5fa201a8bba2..f9d28c23d3dcf4613230b818b309d3d33d9e21ee 100644 (file)
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: shpopen.c,v 1.73 2012-01-24 22:33:01 fwarmerdam Exp $
+ * $Id: shpopen.c,v 1.76 2017-09-10 10:11:36 erouault Exp $
  *
  * Project:  Shapelib
  * Purpose:  Implementation of core Shapefile read/write functions.
@@ -7,13 +7,14 @@
  *
  ******************************************************************************
  * Copyright (c) 1999, 2001, Frank Warmerdam
+ * Copyright (c) 2011-2013, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * This software is available under the following "MIT Style" license,
- * or at the option of the licensee under the LGPL (see LICENSE.LGPL).  This
+ * or at the option of the licensee under the LGPL (see COPYING).  This
  * option is discussed in more detail in shapelib.html.
  *
  * --
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
  ******************************************************************************
  *
  * $Log: shpopen.c,v $
+ * Revision 1.76  2017-09-10 10:11:36  erouault
+ * * shpopen.c: resync with GDAL copy. Make sure to zero terminate all
+ * error messages. And fix regression regarding re-writing the last shape
+ * of a file (https://trac.osgeo.org/gdal/ticket/7031)
+ *
+ * Revision 1.75  2016-12-05 12:44:05  erouault
+ * * Major overhaul of Makefile build system to use autoconf/automake.
+ *
+ * * Warning fixes in contrib/
+ *
+ * Revision 1.74  2016-12-04 15:30:15  erouault
+ * * shpopen.c, dbfopen.c, shptree.c, shapefil.h: resync with
+ * GDAL Shapefile driver. Mostly cleanups. SHPObject and DBFInfo
+ * structures extended with new members. New functions:
+ * DBFSetLastModifiedDate, SHPOpenLLEx, SHPRestoreSHX,
+ * SHPSetFastModeReadObject
+ *
+ * * sbnsearch.c: new file to implement original ESRI .sbn spatial
+ * index reading. (no write support). New functions:
+ * SBNOpenDiskTree, SBNCloseDiskTree, SBNSearchDiskTree,
+ * SBNSearchDiskTreeInteger, SBNSearchFreeIds
+ *
+ * * Makefile, makefile.vc, CMakeLists.txt, shapelib.def: updates
+ * with new file and symbols.
+ *
+ * * commit: helper script to cvs commit
+ *
  * Revision 1.73  2012-01-24 22:33:01  fwarmerdam
  * fix memory leak on failure to open .shp (gdal #4410)
  *
  * avoid c++ comments
  *
  * Revision 1.38  2002/05/07 16:43:39  warmerda
- * Removed debugging printf.
+ * Removed debugging printf()
  *
  * Revision 1.37  2002/04/10 17:35:22  warmerda
  * fixed bug in ring reversal code
  * move pabyRec into SHPInfo for thread safety
  *
  * Revision 1.33  2001/07/03 12:18:15  warmerda
- * Improved cleanup if SHX not found, provied by Riccardo Cohen.
+ * Improved cleanup if SHX not found, provided by Riccardo Cohen.
  *
  * Revision 1.32  2001/06/22 01:58:07  warmerda
  * be more careful about establishing initial bounds in face of NULL shapes
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
-// GPSBabel-local: add stdint for MSVC.
-#include <stdint.h>
+#include <errno.h>
 
-SHP_CVSID("$Id: shpopen.c,v 1.73 2012-01-24 22:33:01 fwarmerdam Exp $")
+SHP_CVSID("$Id: shpopen.c,v 1.76 2017-09-10 10:11:36 erouault Exp $")
 
 typedef unsigned char uchar;
 
@@ -296,14 +323,33 @@ typedef unsigned int            int32;
 #  define MAX(a,b)      ((a>b) ? a : b)
 #endif
 
-#if defined(WIN32) || defined(_WIN32)
+#ifndef USE_CPL
+#if defined(_MSC_VER)
+# if _MSC_VER < 1900
+#     define snprintf _snprintf
+# endif
+#elif defined(WIN32) || defined(_WIN32)
 #  ifndef snprintf
 #     define snprintf _snprintf
 #  endif
 #endif
+#endif
 
-static int     bBigEndian;
+#ifndef CPL_UNUSED
+#if defined(__GNUC__) && __GNUC__ >= 4
+#  define CPL_UNUSED __attribute((__unused__))
+#else
+#  define CPL_UNUSED
+#endif
+#endif  
 
+#if defined(CPL_LSB)
+#define bBigEndian FALSE
+#elif defined(CPL_MSB)
+#define bBigEndian TRUE
+#else
+static int     bBigEndian;
+#endif
 
 /************************************************************************/
 /*                              SwapWord()                              */
@@ -351,12 +397,12 @@ static void * SfRealloc( void * pMem, int nNewSize )
 void SHPAPI_CALL SHPWriteHeader( SHPHandle psSHP )
 
 {
-    uchar      abyHeader[100];
+    uchar      abyHeader[100] = { 0 };
     int                i;
     int32      i32;
     double     dValue;
     int32      *panSHX;
-    
+
     if (psSHP->fpSHX == NULL)
     {
         psSHP->sHooks.Error( "SHPWriteHeader failed : SHX file is closed");
@@ -366,8 +412,6 @@ void SHPAPI_CALL SHPWriteHeader( SHPHandle psSHP )
 /* -------------------------------------------------------------------- */
 /*      Prepare header block for .shp file.                             */
 /* -------------------------------------------------------------------- */
-    for( i = 0; i < 100; i++ )
-        abyHeader[i] = 0;
 
     abyHeader[2] = 0x27;                               /* magic cookie */
     abyHeader[3] = 0x0a;
@@ -375,11 +419,11 @@ void SHPAPI_CALL SHPWriteHeader( SHPHandle psSHP )
     i32 = psSHP->nFileSize/2;                          /* file size */
     ByteCopy( &i32, abyHeader+24, 4 );
     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
-    
+
     i32 = 1000;                                                /* version */
     ByteCopy( &i32, abyHeader+28, 4 );
     if( bBigEndian ) SwapWord( 4, abyHeader+28 );
-    
+
     i32 = psSHP->nShapeType;                           /* shape type */
     ByteCopy( &i32, abyHeader+32, 4 );
     if( bBigEndian ) SwapWord( 4, abyHeader+32 );
@@ -419,10 +463,15 @@ void SHPAPI_CALL SHPWriteHeader( SHPHandle psSHP )
 /* -------------------------------------------------------------------- */
 /*      Write .shp file header.                                         */
 /* -------------------------------------------------------------------- */
-    if( psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 0 ) != 0 
+    if( psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 0 ) != 0
         || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHP ) != 1 )
     {
-        psSHP->sHooks.Error( "Failure writing .shp header" );
+        char szErrorMsg[200];
+
+        snprintf( szErrorMsg, sizeof(szErrorMsg),
+                 "Failure writing .shp header: %s", strerror(errno) );
+        szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+        psSHP->sHooks.Error( szErrorMsg );
         return;
     }
 
@@ -432,11 +481,17 @@ void SHPAPI_CALL SHPWriteHeader( SHPHandle psSHP )
     i32 = (psSHP->nRecords * 2 * sizeof(int32) + 100)/2;   /* file size */
     ByteCopy( &i32, abyHeader+24, 4 );
     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
-    
-    if( psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 0 ) != 0 
+
+    if( psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 0 ) != 0
         || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHX ) != 1 )
     {
-        psSHP->sHooks.Error( "Failure writing .shx header" );
+        char szErrorMsg[200];
+
+        snprintf( szErrorMsg, sizeof(szErrorMsg),
+                 "Failure writing .shx header: %s", strerror(errno) );
+        szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+        psSHP->sHooks.Error( szErrorMsg );
+
         return;
     }
 
@@ -444,6 +499,11 @@ void SHPAPI_CALL SHPWriteHeader( SHPHandle psSHP )
 /*      Write out the .shx contents.                                    */
 /* -------------------------------------------------------------------- */
     panSHX = (int32 *) malloc(sizeof(int32) * 2 * psSHP->nRecords);
+    if( panSHX == NULL )
+    {
+        psSHP->sHooks.Error( "Failure allocatin panSHX" );
+        return;
+    }
 
     for( i = 0; i < psSHP->nRecords; i++ )
     {
@@ -453,10 +513,15 @@ void SHPAPI_CALL SHPWriteHeader( SHPHandle psSHP )
         if( !bBigEndian ) SwapWord( 4, panSHX+i*2+1 );
     }
 
-    if( (int)psSHP->sHooks.FWrite( panSHX, sizeof(int32)*2, psSHP->nRecords, psSHP->fpSHX ) 
+    if( (int)psSHP->sHooks.FWrite( panSHX, sizeof(int32)*2, psSHP->nRecords, psSHP->fpSHX )
         != psSHP->nRecords )
     {
-        psSHP->sHooks.Error( "Failure writing .shx contents" );
+        char szErrorMsg[200];
+
+        snprintf( szErrorMsg, sizeof(szErrorMsg),
+                 "Failure writing .shx contents: %s", strerror(errno) );
+        szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+        psSHP->sHooks.Error( szErrorMsg );
     }
 
     free( panSHX );
@@ -489,18 +554,20 @@ SHPOpen( const char * pszLayer, const char * pszAccess )
 /*      Open the .shp and .shx files based on the basename of the       */
 /*      files or either file name.                                      */
 /************************************************************************/
-   
+
 SHPHandle SHPAPI_CALL
 SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
 
 {
-    char               *pszFullname, *pszBasename;
-    SHPHandle          psSHP;
-    
-    uchar              *pabyBuf;
-    int                        i;
-    double             dValue;
-    
+    char        *pszFullname, *pszBasename;
+    SHPHandle       psSHP;
+
+    uchar       *pabyBuf;
+    int         i;
+    double      dValue;
+    int         bLazySHXLoading = FALSE;
+    size_t nFullnameLen;
+
 /* -------------------------------------------------------------------- */
 /*      Ensure the access string is one of the legal ones.  We          */
 /*      ensure the result string indicates binary to avoid common       */
@@ -510,19 +577,24 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
         || strcmp(pszAccess,"r+") == 0 )
         pszAccess = "r+b";
     else
+    {
+        bLazySHXLoading = strchr(pszAccess, 'l') != NULL;
         pszAccess = "rb";
-    
+    }
+
 /* -------------------------------------------------------------------- */
-/*     Establish the byte order on this machine.                       */
+/*  Establish the byte order on this machine.           */
 /* -------------------------------------------------------------------- */
+#if !defined(bBigEndian)
     i = 1;
     if( *((uchar *) &i) == 1 )
         bBigEndian = FALSE;
     else
         bBigEndian = TRUE;
+#endif
 
 /* -------------------------------------------------------------------- */
-/*     Initialize the info structure.                                  */
+/*  Initialize the info structure.                  */
 /* -------------------------------------------------------------------- */
     psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1);
 
@@ -530,12 +602,12 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
     memcpy( &(psSHP->sHooks), psHooks, sizeof(SAHooks) );
 
 /* -------------------------------------------------------------------- */
-/*     Compute the base (layer) name.  If there is any extension       */
-/*     on the passed in filename we will strip it off.                 */
+/*  Compute the base (layer) name.  If there is any extension   */
+/*  on the passed in filename we will strip it off.         */
 /* -------------------------------------------------------------------- */
     pszBasename = (char *) malloc(strlen(pszLayer)+5);
     strcpy( pszBasename, pszLayer );
-    for( i = strlen(pszBasename)-1; 
+    for( i = (int)strlen(pszBasename)-1;
          i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
              && pszBasename[i] != '\\';
          i-- ) {}
@@ -544,22 +616,24 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
         pszBasename[i] = '\0';
 
 /* -------------------------------------------------------------------- */
-/*     Open the .shp and .shx files.  Note that files pulled from      */
-/*     a PC to Unix with upper case filenames won't work!              */
+/*  Open the .shp and .shx files.  Note that files pulled from  */
+/*  a PC to Unix with upper case filenames won't work!      */
 /* -------------------------------------------------------------------- */
-    pszFullname = (char *) malloc(strlen(pszBasename) + 5);
-    sprintf( pszFullname, "%s.shp", pszBasename ) ;
+    nFullnameLen = strlen(pszBasename) + 5;
+    pszFullname = (char *) malloc(nFullnameLen);
+    snprintf( pszFullname, nFullnameLen, "%s.shp", pszBasename ) ;
     psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
     if( psSHP->fpSHP == NULL )
     {
-        sprintf( pszFullname, "%s.SHP", pszBasename );
+        snprintf( pszFullname, nFullnameLen, "%s.SHP", pszBasename );
         psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
     }
-    
+
     if( psSHP->fpSHP == NULL )
     {
-        char *pszMessage = (char *) malloc(strlen(pszBasename)*2+256);
-        sprintf( pszMessage, "Unable to open %s.shp or %s.SHP.", 
+        size_t nMessageLen = strlen(pszBasename)*2+256;
+        char *pszMessage = (char *) malloc(nMessageLen);
+        snprintf( pszMessage, nMessageLen, "Unable to open %s.shp or %s.SHP.",
                   pszBasename, pszBasename );
         psHooks->Error( pszMessage );
         free( pszMessage );
@@ -571,18 +645,20 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
         return NULL;
     }
 
-    sprintf( pszFullname, "%s.shx", pszBasename );
+    snprintf( pszFullname, nFullnameLen, "%s.shx", pszBasename );
     psSHP->fpSHX =  psSHP->sHooks.FOpen(pszFullname, pszAccess );
     if( psSHP->fpSHX == NULL )
     {
-        sprintf( pszFullname, "%s.SHX", pszBasename );
+        snprintf( pszFullname, nFullnameLen, "%s.SHX", pszBasename );
         psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess );
     }
-    
+
     if( psSHP->fpSHX == NULL )
     {
-        char *pszMessage = (char *) malloc(strlen(pszBasename)*2+256);
-        sprintf( pszMessage, "Unable to open %s.shx or %s.SHX.", 
+        size_t nMessageLen = strlen(pszBasename)*2+256;
+        char *pszMessage = (char *) malloc(nMessageLen);
+        snprintf( pszMessage, nMessageLen, "Unable to open %s.shx or %s.SHX."
+                  "Try --config SHAPE_RESTORE_SHX true to restore or create it",
                   pszBasename, pszBasename );
         psHooks->Error( pszMessage );
         free( pszMessage );
@@ -598,48 +674,52 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
     free( pszBasename );
 
 /* -------------------------------------------------------------------- */
-/*  Read the file size from the SHP file.                              */
+/*  Read the file size from the SHP file.               */
 /* -------------------------------------------------------------------- */
     pabyBuf = (uchar *) malloc(100);
     psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHP );
 
-    psSHP->nFileSize = ((unsigned int)pabyBuf[24] * 256 * 256 * 256
-                        + (unsigned int)pabyBuf[25] * 256 * 256
-                        + (unsigned int)pabyBuf[26] * 256
-                        + (unsigned int)pabyBuf[27]) * 2;
+    psSHP->nFileSize = ((unsigned int)pabyBuf[24]<<24)|(pabyBuf[25]<<16)|
+                        (pabyBuf[26]<<8)|pabyBuf[27];
+    if( psSHP->nFileSize < UINT_MAX / 2 )
+        psSHP->nFileSize *= 2;
+    else
+        psSHP->nFileSize = (UINT_MAX / 2) * 2;
 
 /* -------------------------------------------------------------------- */
 /*  Read SHX file Header info                                           */
 /* -------------------------------------------------------------------- */
-    if( psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHX ) != 1 
-        || pabyBuf[0] != 0 
-        || pabyBuf[1] != 0 
-        || pabyBuf[2] != 0x27 
+    if( psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHX ) != 1
+        || pabyBuf[0] != 0
+        || pabyBuf[1] != 0
+        || pabyBuf[2] != 0x27
         || (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d) )
     {
         psSHP->sHooks.Error( ".shx file is unreadable, or corrupt." );
         psSHP->sHooks.FClose( psSHP->fpSHP );
         psSHP->sHooks.FClose( psSHP->fpSHX );
+        free( pabyBuf );
         free( psSHP );
 
         return( NULL );
     }
 
-    psSHP->nRecords = pabyBuf[27] + pabyBuf[26] * 256
-        + pabyBuf[25] * 256 * 256 + pabyBuf[24] * 256 * 256 * 256;
-    psSHP->nRecords = (psSHP->nRecords*2 - 100) / 8;
+    psSHP->nRecords = pabyBuf[27]|(pabyBuf[26]<<8)|(pabyBuf[25]<<16)|
+                      ((pabyBuf[24] & 0x7F)<<24);
+    psSHP->nRecords = (psSHP->nRecords - 50) / 4;
 
     psSHP->nShapeType = pabyBuf[32];
 
     if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 )
     {
-        char szError[200];
-        
-        sprintf( szError, 
+        char szErrorMsg[200];
+
+        snprintf( szErrorMsg, sizeof(szErrorMsg),
                  "Record count in .shp header is %d, which seems\n"
                  "unreasonable.  Assuming header is corrupt.",
                  psSHP->nRecords );
-        psSHP->sHooks.Error( szError );                                       
+        szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+        psSHP->sHooks.Error( szErrorMsg );
         psSHP->sHooks.FClose( psSHP->fpSHP );
         psSHP->sHooks.FClose( psSHP->fpSHX );
         free( psSHP );
@@ -648,6 +728,21 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
         return( NULL );
     }
 
+    /* If a lot of records are advertized, check that the file is big enough */
+    /* to hold them */
+    if( psSHP->nRecords >= 1024 * 1024 )
+    {
+        SAOffset nFileSize;
+        psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 2 );
+        nFileSize = psSHP->sHooks.FTell( psSHP->fpSHX );
+        if( nFileSize > 100 &&
+            nFileSize/2 < (SAOffset)(psSHP->nRecords * 4 + 50) )
+        {
+            psSHP->nRecords = (int)((nFileSize - 100) / 8);
+        }
+        psSHP->sHooks.FSeek( psSHP->fpSHX, 100, 0 );
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Read the bounds.                                                */
 /* -------------------------------------------------------------------- */
@@ -667,15 +762,15 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
     memcpy( &dValue, pabyBuf+60, 8 );
     psSHP->adBoundsMax[1] = dValue;
 
-    if( bBigEndian ) SwapWord( 8, pabyBuf+68 );                /* z */
+    if( bBigEndian ) SwapWord( 8, pabyBuf+68 );     /* z */
     memcpy( &dValue, pabyBuf+68, 8 );
     psSHP->adBoundsMin[2] = dValue;
-    
+
     if( bBigEndian ) SwapWord( 8, pabyBuf+76 );
     memcpy( &dValue, pabyBuf+76, 8 );
     psSHP->adBoundsMax[2] = dValue;
-    
-    if( bBigEndian ) SwapWord( 8, pabyBuf+84 );                /* z */
+
+    if( bBigEndian ) SwapWord( 8, pabyBuf+84 );     /* z */
     memcpy( &dValue, pabyBuf+84, 8 );
     psSHP->adBoundsMin[3] = dValue;
 
@@ -686,8 +781,8 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
     free( pabyBuf );
 
 /* -------------------------------------------------------------------- */
-/*     Read the .shx file to get the offsets to each record in         */
-/*     the .shp file.                                                  */
+/*  Read the .shx file to get the offsets to each record in     */
+/*  the .shp file.                          */
 /* -------------------------------------------------------------------- */
     psSHP->nMaxRecords = psSHP->nRecords;
 
@@ -695,19 +790,23 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
         malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
     psSHP->panRecSize = (unsigned int *)
         malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
-    pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
+    if( bLazySHXLoading )
+        pabyBuf = NULL;
+    else
+        pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
 
     if (psSHP->panRecOffset == NULL ||
         psSHP->panRecSize == NULL ||
-        pabyBuf == NULL)
+        (!bLazySHXLoading && pabyBuf == NULL))
     {
-        char szError[200];
+        char szErrorMsg[200];
 
-        sprintf(szError, 
+        snprintf( szErrorMsg, sizeof(szErrorMsg),
                 "Not enough memory to allocate requested memory (nRecords=%d).\n"
-                "Probably broken SHP file", 
+                "Probably broken SHP file",
                 psSHP->nRecords );
-        psSHP->sHooks.Error( szError );
+        szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+        psSHP->sHooks.Error( szErrorMsg );
         psSHP->sHooks.FClose( psSHP->fpSHP );
         psSHP->sHooks.FClose( psSHP->fpSHX );
         if (psSHP->panRecOffset) free( psSHP->panRecOffset );
@@ -717,15 +816,23 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
         return( NULL );
     }
 
-    if( (int) psSHP->sHooks.FRead( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX ) 
+    if( bLazySHXLoading )
+    {
+        memset(psSHP->panRecOffset, 0, sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
+        memset(psSHP->panRecSize, 0, sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
+        return( psSHP );
+    }
+
+    if( (int) psSHP->sHooks.FRead( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX )
         != psSHP->nRecords )
     {
-        char szError[200];
+        char szErrorMsg[200];
 
-        sprintf( szError, 
-                 "Failed to read all values for %d records in .shx file.",
-                 psSHP->nRecords );
-        psSHP->sHooks.Error( szError );
+        snprintf( szErrorMsg, sizeof(szErrorMsg),
+                 "Failed to read all values for %d records in .shx file: %s.",
+                 psSHP->nRecords, strerror(errno) );
+        szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+        psSHP->sHooks.Error( szErrorMsg );
 
         /* SHX is short or unreadable for some reason. */
         psSHP->sHooks.FClose( psSHP->fpSHP );
@@ -737,7 +844,7 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
 
         return( NULL );
     }
-    
+
     /* In read-only mode, we can close the SHX now */
     if (strcmp(pszAccess, "rb") == 0)
     {
@@ -747,7 +854,7 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
 
     for( i = 0; i < psSHP->nRecords; i++ )
     {
-        int32          nOffset, nLength;
+        unsigned int        nOffset, nLength;
 
         memcpy( &nOffset, pabyBuf + i * 8, 4 );
         if( !bBigEndian ) SwapWord( 4, &nOffset );
@@ -755,6 +862,30 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
         memcpy( &nLength, pabyBuf + i * 8 + 4, 4 );
         if( !bBigEndian ) SwapWord( 4, &nLength );
 
+        if( nOffset > (unsigned int)INT_MAX )
+        {
+            char str[128];
+            snprintf( str, sizeof(str),
+                    "Invalid offset for entity %d", i);
+            str[sizeof(str)-1] = '\0';
+
+            psSHP->sHooks.Error( str );
+            SHPClose(psSHP);
+            free( pabyBuf );
+            return NULL;
+        }
+        if( nLength > (unsigned int)(INT_MAX / 2 - 4) )
+        {
+            char str[128];
+            snprintf( str, sizeof(str),
+                    "Invalid length for entity %d", i);
+            str[sizeof(str)-1] = '\0';
+
+            psSHP->sHooks.Error( str );
+            SHPClose(psSHP);
+            free( pabyBuf );
+            return NULL;
+        }
         psSHP->panRecOffset[i] = nOffset*2;
         psSHP->panRecSize[i] = nLength*2;
     }
@@ -763,6 +894,225 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
     return( psSHP );
 }
 
+/************************************************************************/
+/*                              SHPOpenLLEx()                           */
+/*                                                                      */
+/*      Open the .shp and .shx files based on the basename of the       */
+/*      files or either file name. It generally invokes SHPRestoreSHX() */
+/*      in case when bRestoreSHX equals true.                           */
+/************************************************************************/
+
+SHPHandle SHPAPI_CALL
+SHPOpenLLEx( const char * pszLayer, const char * pszAccess, SAHooks *psHooks,
+            int bRestoreSHX )
+
+{
+    if ( !bRestoreSHX ) return SHPOpenLL ( pszLayer, pszAccess, psHooks );
+    else
+    {
+        if ( SHPRestoreSHX ( pszLayer, pszAccess, psHooks ) )
+        {
+            return SHPOpenLL ( pszLayer, pszAccess, psHooks );
+        }
+    }
+
+    return( NULL );
+}
+
+/************************************************************************/
+/*                              SHPRestoreSHX()                         */
+/*                                                                      */
+/*      Restore .SHX file using associated .SHP file.                   */
+/*                                                                      */
+/************************************************************************/
+
+int       SHPAPI_CALL
+SHPRestoreSHX ( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
+
+{
+    char            *pszFullname, *pszBasename;
+    SAFile          fpSHP, fpSHX;
+
+
+    uchar           *pabyBuf;
+    int             i;
+    size_t          nFullnameLen;
+    unsigned int    nSHPFilesize;
+
+    size_t          nMessageLen;
+    char            *pszMessage;
+
+    unsigned int    nCurrentRecordOffset = 0;
+    unsigned int    nCurrentSHPOffset = 100;
+    size_t          nRealSHXContentSize = 100;
+
+    const char      pszSHXAccess[] = "w+b";
+    char            *pabySHXHeader;
+    char            abyReadedRecord[8];
+    unsigned int    niRecord = 0;
+    unsigned int    nRecordLength = 0;
+    unsigned int    nRecordOffset = 50;
+
+/* -------------------------------------------------------------------- */
+/*      Ensure the access string is one of the legal ones.  We          */
+/*      ensure the result string indicates binary to avoid common       */
+/*      problems on Windows.                                            */
+/* -------------------------------------------------------------------- */
+    if( strcmp(pszAccess,"rb+") == 0 || strcmp(pszAccess,"r+b") == 0
+        || strcmp(pszAccess,"r+") == 0 )
+        pszAccess = "r+b";
+    else
+    {
+        pszAccess = "rb";
+    }
+
+/* -------------------------------------------------------------------- */
+/*  Establish the byte order on this machine.                           */
+/* -------------------------------------------------------------------- */
+#if !defined(bBigEndian)
+    i = 1;
+    if( *((uchar *) &i) == 1 )
+        bBigEndian = FALSE;
+    else
+        bBigEndian = TRUE;
+#endif
+
+/* -------------------------------------------------------------------- */
+/*  Compute the base (layer) name.  If there is any extension           */
+/*  on the passed in filename we will strip it off.                     */
+/* -------------------------------------------------------------------- */
+    pszBasename = (char *) malloc(strlen(pszLayer)+5);
+    strcpy( pszBasename, pszLayer );
+    for( i = (int)strlen(pszBasename)-1;
+         i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
+             && pszBasename[i] != '\\';
+         i-- ) {}
+
+    if( pszBasename[i] == '.' )
+        pszBasename[i] = '\0';
+
+/* -------------------------------------------------------------------- */
+/*  Open the .shp file.  Note that files pulled from                    */
+/*  a PC to Unix with upper case filenames won't work!                  */
+/* -------------------------------------------------------------------- */
+    nFullnameLen = strlen(pszBasename) + 5;
+    pszFullname = (char *) malloc(nFullnameLen);
+    snprintf( pszFullname, nFullnameLen, "%s.shp", pszBasename ) ;
+    fpSHP = psHooks->FOpen(pszFullname, pszAccess );
+    if( fpSHP == NULL )
+    {
+        snprintf( pszFullname, nFullnameLen, "%s.SHP", pszBasename );
+        fpSHP = psHooks->FOpen(pszFullname, pszAccess );
+    }
+
+    if( fpSHP == NULL )
+    {
+        nMessageLen = strlen(pszBasename)*2+256;
+        pszMessage = (char *) malloc(nMessageLen);
+        snprintf( pszMessage, nMessageLen, "Unable to open %s.shp or %s.SHP.",
+                  pszBasename, pszBasename );
+        psHooks->Error( pszMessage );
+        free( pszMessage );
+
+        free( pszBasename );
+        free( pszFullname );
+
+        return( 0 );
+    }
+
+/* -------------------------------------------------------------------- */
+/*  Read the file size from the SHP file.                               */
+/* -------------------------------------------------------------------- */
+    pabyBuf = (uchar *) malloc(100);
+    psHooks->FRead( pabyBuf, 100, 1, fpSHP );
+
+    nSHPFilesize = ((unsigned int)pabyBuf[24]<<24)|(pabyBuf[25]<<16)|
+                   (pabyBuf[26]<<8)|pabyBuf[27];
+    if( nSHPFilesize < UINT_MAX / 2 )
+        nSHPFilesize *= 2;
+    else
+        nSHPFilesize = (UINT_MAX / 2) * 2;
+
+    snprintf( pszFullname, nFullnameLen, "%s.shx", pszBasename );
+    fpSHX = psHooks->FOpen( pszFullname, pszSHXAccess );
+
+    if( fpSHX == NULL )
+    {
+        nMessageLen = strlen( pszBasename ) * 2 + 256;
+        pszMessage = (char *) malloc( nMessageLen );
+        snprintf( pszMessage, nMessageLen, "Error opening file %s.shx for writing",
+                 pszBasename );
+        psHooks->Error( pszMessage );
+        free( pszMessage );
+
+        psHooks->FClose( fpSHX );
+
+        free( pabyBuf );
+        free( pszBasename );
+        free( pszFullname );
+
+        return( 0 );
+    }
+
+/* -------------------------------------------------------------------- */
+/*  Open SHX and create it using SHP file content.                      */
+/* -------------------------------------------------------------------- */
+    psHooks->FSeek( fpSHP, 100, 0 );
+    pabySHXHeader = (char *) malloc ( 100 );
+    memcpy( pabySHXHeader, pabyBuf, 100 );
+    psHooks->FWrite( pabySHXHeader, 100, 1, fpSHX );
+
+    while( nCurrentSHPOffset < nSHPFilesize )
+    {
+        if( psHooks->FRead( &niRecord, 4, 1, fpSHP ) == 1 &&
+            psHooks->FRead( &nRecordLength, 4, 1, fpSHP ) == 1)
+        {
+            if( !bBigEndian ) SwapWord( 4, &nRecordOffset );
+            memcpy( abyReadedRecord, &nRecordOffset, 4 );
+            memcpy( abyReadedRecord + 4, &nRecordLength, 4 );
+
+            psHooks->FWrite( abyReadedRecord, 8, 1, fpSHX );
+
+            if ( !bBigEndian ) SwapWord( 4, &nRecordOffset );
+            if ( !bBigEndian ) SwapWord( 4, &nRecordLength );
+            nRecordOffset += nRecordLength + 4;
+            nCurrentRecordOffset += 8;
+            nCurrentSHPOffset += 8 + nRecordLength * 2;
+
+            psHooks->FSeek( fpSHP, nCurrentSHPOffset, 0 );
+            nRealSHXContentSize += 8;
+        }
+        else
+        {
+            psHooks->Error( "Error parsing .shp to restore .shx"  );
+
+            psHooks->FClose( fpSHX );
+            psHooks->FClose( fpSHP );
+
+            free( pabySHXHeader );
+            free( pszBasename );
+            free( pszFullname );
+
+            return( 0 );
+        }
+    }
+
+    nRealSHXContentSize /= 2; // Bytes counted -> WORDs
+    if( !bBigEndian ) SwapWord( 4, &nRealSHXContentSize );
+    psHooks->FSeek( fpSHX, 24, 0 );
+    psHooks->FWrite( &nRealSHXContentSize, 4, 1, fpSHX );
+
+    psHooks->FClose( fpSHP );
+    psHooks->FClose( fpSHX );
+
+    free ( pabyBuf );
+    free ( pszFullname );
+    free ( pszBasename );
+    free ( pabySHXHeader );
+
+    return( 1 );
+}
+
 /************************************************************************/
 /*                              SHPClose()                              */
 /*                                                                     */
@@ -796,10 +1146,41 @@ SHPClose(SHPHandle psSHP )
     {
         free( psSHP->pabyRec );
     }
-    
+
+    if( psSHP->pabyObjectBuf != NULL )
+    {
+        free( psSHP->pabyObjectBuf );
+    }
+    if( psSHP->psCachedObject != NULL )
+    {
+        free( psSHP->psCachedObject );
+    }
+
     free( psSHP );
 }
 
+/************************************************************************/
+/*                    SHPSetFastModeReadObject()                        */
+/************************************************************************/
+
+/* If setting bFastMode = TRUE, the content of SHPReadObject() is owned by the SHPHandle. */
+/* So you cannot have 2 valid instances of SHPReadObject() simultaneously. */
+/* The SHPObject padfZ and padfM members may be NULL depending on the geometry */
+/* type. It is illegal to free at hand any of the pointer members of the SHPObject structure */
+void SHPAPI_CALL SHPSetFastModeReadObject( SHPHandle hSHP, int bFastMode )
+{
+    if( bFastMode )
+    {
+        if( hSHP->psCachedObject == NULL )
+        {
+            hSHP->psCachedObject = (SHPObject*) calloc(1, sizeof(SHPObject));
+            assert( hSHP->psCachedObject != NULL );
+        }
+    }
+
+    hSHP->bFastModeReadObject = bFastMode;
+}
+
 /************************************************************************/
 /*                             SHPGetInfo()                             */
 /*                                                                      */
@@ -815,7 +1196,7 @@ SHPGetInfo(SHPHandle psSHP, int * pnEntities, int * pnShapeType,
 
     if( psSHP == NULL )
         return;
-    
+
     if( pnEntities != NULL )
         *pnEntities = psSHP->nRecords;
 
@@ -866,15 +1247,18 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
     uchar      abyHeader[100];
     int32      i32;
     double     dValue;
-    
+    size_t      nFullnameLen;
+
 /* -------------------------------------------------------------------- */
 /*      Establish the byte order on this system.                        */
 /* -------------------------------------------------------------------- */
+#if !defined(bBigEndian)
     i = 1;
     if( *((uchar *) &i) == 1 )
         bBigEndian = FALSE;
     else
         bBigEndian = TRUE;
+#endif
 
 /* -------------------------------------------------------------------- */
 /*     Compute the base (layer) name.  If there is any extension       */
@@ -882,7 +1266,7 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
 /* -------------------------------------------------------------------- */
     pszBasename = (char *) malloc(strlen(pszLayer)+5);
     strcpy( pszBasename, pszLayer );
-    for( i = strlen(pszBasename)-1; 
+    for( i = (int)strlen(pszBasename)-1;
          i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
              && pszBasename[i] != '\\';
          i-- ) {}
@@ -893,20 +1277,30 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
 /* -------------------------------------------------------------------- */
 /*      Open the two files so we can write their headers.               */
 /* -------------------------------------------------------------------- */
-    pszFullname = (char *) malloc(strlen(pszBasename) + 5);
-    sprintf( pszFullname, "%s.shp", pszBasename );
+    nFullnameLen = strlen(pszBasename) + 5;
+    pszFullname = (char *) malloc(nFullnameLen);
+    snprintf( pszFullname, nFullnameLen, "%s.shp", pszBasename );
     fpSHP = psHooks->FOpen(pszFullname, "wb" );
     if( fpSHP == NULL )
     {
-        psHooks->Error( "Failed to create file .shp file." );
+        char szErrorMsg[200];
+        snprintf( szErrorMsg, sizeof(szErrorMsg),
+                 "Failed to create file %s: %s",
+                  pszFullname, strerror(errno) );
+        psHooks->Error( szErrorMsg );
+
         goto error;
     }
 
-    sprintf( pszFullname, "%s.shx", pszBasename );
+    snprintf( pszFullname, nFullnameLen, "%s.shx", pszBasename );
     fpSHX = psHooks->FOpen(pszFullname, "wb" );
     if( fpSHX == NULL )
     {
-        psHooks->Error( "Failed to create file .shx file." );
+        char szErrorMsg[200];
+        snprintf( szErrorMsg, sizeof(szErrorMsg),
+                 "Failed to create file %s: %s",
+                  pszFullname, strerror(errno) );
+        psHooks->Error( szErrorMsg );
         goto error;
     }
 
@@ -916,8 +1310,7 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
 /* -------------------------------------------------------------------- */
 /*      Prepare header block for .shp file.                             */
 /* -------------------------------------------------------------------- */
-    for( i = 0; i < 100; i++ )
-        abyHeader[i] = 0;
+    memset( abyHeader, 0, sizeof(abyHeader) );
 
     abyHeader[2] = 0x27;                               /* magic cookie */
     abyHeader[3] = 0x0a;
@@ -925,11 +1318,11 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
     i32 = 50;                                          /* file size */
     ByteCopy( &i32, abyHeader+24, 4 );
     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
-    
+
     i32 = 1000;                                                /* version */
     ByteCopy( &i32, abyHeader+28, 4 );
     if( bBigEndian ) SwapWord( 4, abyHeader+28 );
-    
+
     i32 = nShapeType;                                  /* shape type */
     ByteCopy( &i32, abyHeader+32, 4 );
     if( bBigEndian ) SwapWord( 4, abyHeader+32 );
@@ -945,7 +1338,13 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
 /* -------------------------------------------------------------------- */
     if( psHooks->FWrite( abyHeader, 100, 1, fpSHP ) != 1 )
     {
-        psHooks->Error( "Failed to write .shp header." );
+        char szErrorMsg[200];
+
+        snprintf( szErrorMsg, sizeof(szErrorMsg),
+                 "Failed to write .shp header: %s", strerror(errno) );
+        szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+        psHooks->Error( szErrorMsg );
+
         goto error;
     }
 
@@ -955,10 +1354,16 @@ SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks )
     i32 = 50;                                          /* file size */
     ByteCopy( &i32, abyHeader+24, 4 );
     if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
-    
+
     if( psHooks->FWrite( abyHeader, 100, 1, fpSHX ) != 1 )
     {
-        psHooks->Error( "Failed to write .shx header." );
+        char szErrorMsg[200];
+
+        snprintf( szErrorMsg, sizeof(szErrorMsg),
+                 "Failure writing .shx header: %s", strerror(errno) );
+        szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+        psHooks->Error( szErrorMsg );
+
         goto error;
     }
 
@@ -1014,7 +1419,7 @@ SHPComputeExtents( SHPObject * psObject )
 
 {
     int                i;
-    
+
 /* -------------------------------------------------------------------- */
 /*      Build extents for this object.                                  */
 /* -------------------------------------------------------------------- */
@@ -1025,7 +1430,7 @@ SHPComputeExtents( SHPObject * psObject )
         psObject->dfZMin = psObject->dfZMax = psObject->padfZ[0];
         psObject->dfMMin = psObject->dfMMax = psObject->padfM[0];
     }
-    
+
     for( i = 0; i < psObject->nVertices; i++ )
     {
         psObject->dfXMin = MIN(psObject->dfXMin, psObject->padfX[i]);
@@ -1106,10 +1511,10 @@ SHPCreateObject( int nSHPType, int nShapeId, int nParts,
 
         psObject->panPartStart[0] = 0;
         psObject->panPartType[0] = SHPP_RING;
-        
+
         for( i = 0; i < nParts; i++ )
         {
-            if( psObject->panPartStart != NULL )
+            if( panPartStart != NULL )
                 psObject->panPartStart[i] = panPartStart[i];
 
             if( panPartType != NULL )
@@ -1127,24 +1532,26 @@ SHPCreateObject( int nSHPType, int nShapeId, int nParts,
 /* -------------------------------------------------------------------- */
     if( nVertices > 0 )
     {
-        psObject->padfX = (double *) calloc(sizeof(double),nVertices);
-        psObject->padfY = (double *) calloc(sizeof(double),nVertices);
-        psObject->padfZ = (double *) calloc(sizeof(double),nVertices);
-        psObject->padfM = (double *) calloc(sizeof(double),nVertices);
-
-        for( i = 0; i < nVertices; i++ )
-        {
-            if( padfX != NULL )
-                psObject->padfX[i] = padfX[i];
-            if( padfY != NULL )
-                psObject->padfY[i] = padfY[i];
-            if( padfZ != NULL && bHasZ )
-                psObject->padfZ[i] = padfZ[i];
-            if( padfM != NULL && bHasM )
-                psObject->padfM[i] = padfM[i];
-        }
+        size_t nSize = sizeof(double) * nVertices;
+        psObject->padfX = (double *) padfX ? malloc(nSize) :
+                                             calloc(sizeof(double),nVertices);
+        psObject->padfY = (double *) padfY ? malloc(nSize) :
+                                             calloc(sizeof(double),nVertices);
+        psObject->padfZ = (double *) padfZ && bHasZ ? malloc(nSize) :
+                                             calloc(sizeof(double),nVertices);
+        psObject->padfM = (double *) padfM && bHasM ? malloc(nSize) :
+                                             calloc(sizeof(double),nVertices);
+        if( padfX != NULL )
+            memcpy(psObject->padfX, padfX, nSize);
+        if( padfY != NULL )
+            memcpy(psObject->padfY, padfY, nSize);
+        if( padfZ != NULL && bHasZ )
+            memcpy(psObject->padfZ, padfZ, nSize);
         if( padfM != NULL && bHasM )
+        {
+            memcpy(psObject->padfM, padfM, nSize);
             psObject->bMeasureIsUsed = TRUE;
+        }
     }
 
 /* -------------------------------------------------------------------- */
@@ -1172,7 +1579,7 @@ SHPCreateSimpleObject( int nSHPType, int nVertices,
     return( SHPCreateObject( nSHPType, -1, 0, NULL, NULL,
                              nVertices, padfX, padfY, padfZ, NULL ) );
 }
-                                  
+
 /************************************************************************/
 /*                           SHPWriteObject()                           */
 /*                                                                      */
@@ -1182,12 +1589,14 @@ SHPCreateSimpleObject( int nSHPType, int nVertices,
 
 int SHPAPI_CALL
 SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
-                     
+
 {
     unsigned int               nRecordOffset, nRecordSize=0;
     int i;
     uchar      *pabyRec;
     int32      i32;
+    int     bAppendToLastRecord = FALSE;
+    int     bAppendToFile = FALSE;
 
     psSHP->bUpdated = TRUE;
 
@@ -1195,7 +1604,7 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
 /*      Ensure that shape object matches the type of the file it is     */
 /*      being written to.                                               */
 /* -------------------------------------------------------------------- */
-    assert( psObject->nSHPType == psSHP->nShapeType 
+    assert( psObject->nSHPType == psSHP->nShapeType
             || psObject->nSHPType == SHPT_NULL );
 
 /* -------------------------------------------------------------------- */
@@ -1203,7 +1612,7 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
 /*      assertion, or if they are disabled, set the shapeid to -1       */
 /*      for appends.                                                    */
 /* -------------------------------------------------------------------- */
-    assert( nShapeId == -1 
+    assert( nShapeId == -1
             || (nShapeId >= 0 && nShapeId < psSHP->nRecords) );
 
     if( nShapeId != -1 && nShapeId >= psSHP->nRecords )
@@ -1214,33 +1623,45 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
 /* -------------------------------------------------------------------- */
     if( nShapeId == -1 && psSHP->nRecords+1 > psSHP->nMaxRecords )
     {
-        psSHP->nMaxRecords =(int) ( psSHP->nMaxRecords * 1.3 + 100);
+        int nNewMaxRecords = psSHP->nMaxRecords + psSHP->nMaxRecords / 3 + 100;
+        unsigned int* panRecOffsetNew;
+        unsigned int* panRecSizeNew;
+
+        panRecOffsetNew = (unsigned int *)
+            SfRealloc(psSHP->panRecOffset,sizeof(unsigned int) * nNewMaxRecords );
+        if( panRecOffsetNew == NULL )
+            return -1;
+        psSHP->panRecOffset = panRecOffsetNew;
+
+        panRecSizeNew = (unsigned int *)
+            SfRealloc(psSHP->panRecSize,sizeof(unsigned int) * nNewMaxRecords );
+        if( panRecSizeNew == NULL )
+            return -1;
+        psSHP->panRecSize = panRecSizeNew;
 
-        psSHP->panRecOffset = (unsigned int *) 
-            SfRealloc(psSHP->panRecOffset,sizeof(unsigned int) * psSHP->nMaxRecords );
-        psSHP->panRecSize = (unsigned int *) 
-            SfRealloc(psSHP->panRecSize,sizeof(unsigned int) * psSHP->nMaxRecords );
+        psSHP->nMaxRecords = nNewMaxRecords;
     }
 
 /* -------------------------------------------------------------------- */
 /*      Initialize record.                                              */
 /* -------------------------------------------------------------------- */
-    pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double) 
+    pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double)
                                + psObject->nParts * 8 + 128);
-    
+    if( pabyRec == NULL )
+        return -1;
+
 /* -------------------------------------------------------------------- */
 /*  Extract vertices for a Polygon or Arc.                             */
 /* -------------------------------------------------------------------- */
     if( psObject->nSHPType == SHPT_POLYGON
         || psObject->nSHPType == SHPT_POLYGONZ
         || psObject->nSHPType == SHPT_POLYGONM
-        || psObject->nSHPType == SHPT_ARC 
+        || psObject->nSHPType == SHPT_ARC
         || psObject->nSHPType == SHPT_ARCZ
         || psObject->nSHPType == SHPT_ARCM
         || psObject->nSHPType == SHPT_MULTIPATCH )
     {
         int32          nPoints, nParts;
-        int                    i;
 
         nPoints = psObject->nVertices;
         nParts = psObject->nParts;
@@ -1290,7 +1711,7 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
 
             if( bBigEndian )
                 SwapWord( 8, pabyRec + nRecordSize );
-            
+
             if( bBigEndian )
                 SwapWord( 8, pabyRec + nRecordSize + 8 );
 
@@ -1307,7 +1728,7 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
             ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
             nRecordSize += 8;
-            
+
             ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
             nRecordSize += 8;
@@ -1326,16 +1747,16 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
         if( psObject->bMeasureIsUsed
             && (psObject->nSHPType == SHPT_POLYGONM
                 || psObject->nSHPType == SHPT_ARCM
-#ifndef DISABLE_MULTIPATCH_MEASURE            
+#ifndef DISABLE_MULTIPATCH_MEASURE
                 || psObject->nSHPType == SHPT_MULTIPATCH
-#endif            
+#endif
                 || psObject->nSHPType == SHPT_POLYGONZ
                 || psObject->nSHPType == SHPT_ARCZ) )
         {
             ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
             nRecordSize += 8;
-            
+
             ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
             nRecordSize += 8;
@@ -1357,7 +1778,6 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
              || psObject->nSHPType == SHPT_MULTIPOINTM )
     {
         int32          nPoints;
-        int                    i;
 
         nPoints = psObject->nVertices;
 
@@ -1365,7 +1785,7 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
 
         if( bBigEndian ) SwapWord( 4, &nPoints );
         ByteCopy( &nPoints, pabyRec + 44, 4 );
-       
+
         for( i = 0; i < psObject->nVertices; i++ )
         {
             ByteCopy( psObject->padfX + i, pabyRec + 48 + i*16, 8 );
@@ -1386,7 +1806,7 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
             ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
             nRecordSize += 8;
-            
+
             for( i = 0; i < psObject->nVertices; i++ )
             {
                 ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
@@ -1406,7 +1826,7 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
             ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
             nRecordSize += 8;
-            
+
             for( i = 0; i < psObject->nVertices; i++ )
             {
                 ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
@@ -1430,14 +1850,14 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
         if( bBigEndian ) SwapWord( 8, pabyRec + 20 );
 
         nRecordSize = 28;
-        
+
         if( psObject->nSHPType == SHPT_POINTZ )
         {
             ByteCopy( psObject->padfZ, pabyRec + nRecordSize, 8 );
             if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
             nRecordSize += 8;
         }
-        
+
         if( psObject->bMeasureIsUsed
             && (psObject->nSHPType == SHPT_POINTZ
                 || psObject->nSHPType == SHPT_POINTM) )
@@ -1464,40 +1884,43 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
 
 /* -------------------------------------------------------------------- */
 /*      Establish where we are going to put this record. If we are      */
-/*      rewriting and existing record, and it will fit, then put it     */
-/*      back where the original came from.  Otherwise write at the end. */
+/*      rewriting the last record of the file, then we can update it in */
+/*      place. Otherwise if rewriting an existing record, and it will   */
+/*      fit, then put it  back where the original came from.  Otherwise */
+/*      write at the end.                                               */
 /* -------------------------------------------------------------------- */
-    if( nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize-8 )
+    if( nShapeId != -1 && psSHP->panRecOffset[nShapeId] +
+                        psSHP->panRecSize[nShapeId] + 8 == psSHP->nFileSize )
+    {
+        nRecordOffset = psSHP->panRecOffset[nShapeId];
+        bAppendToLastRecord = TRUE;
+    }
+    else if( nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize-8 )
     {
-        unsigned int nExpectedSize = psSHP->nFileSize + nRecordSize;
-        if( nExpectedSize < psSHP->nFileSize ) // due to unsigned int overflow
+        if( psSHP->nFileSize > UINT_MAX - nRecordSize)
         {
             char str[128];
-            sprintf( str, "Failed to write shape object. "
+            snprintf( str, sizeof(str), "Failed to write shape object. "
                      "File size cannot reach %u + %u.",
                      psSHP->nFileSize, nRecordSize );
+            str[sizeof(str)-1] = '\0';
             psSHP->sHooks.Error( str );
             free( pabyRec );
             return -1;
         }
 
-        if( nShapeId == -1 )
-            nShapeId = psSHP->nRecords++;
-
-        psSHP->panRecOffset[nShapeId] = nRecordOffset = psSHP->nFileSize;
-        psSHP->panRecSize[nShapeId] = nRecordSize-8;
-        psSHP->nFileSize += nRecordSize;
+        bAppendToFile = TRUE;
+        nRecordOffset = psSHP->nFileSize;
     }
     else
     {
         nRecordOffset = psSHP->panRecOffset[nShapeId];
-        psSHP->panRecSize[nShapeId] = nRecordSize-8;
     }
-    
+
 /* -------------------------------------------------------------------- */
 /*      Set the shape type, record number, and record size.             */
 /* -------------------------------------------------------------------- */
-    i32 = nShapeId+1;                                  /* record # */
+    i32 = (nShapeId < 0) ? psSHP->nRecords+1 : nShapeId+1;                                     /* record # */
     if( !bBigEndian ) SwapWord( 4, &i32 );
     ByteCopy( &i32, pabyRec, 4 );
 
@@ -1514,19 +1937,47 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
 /* -------------------------------------------------------------------- */
     if( psSHP->sHooks.FSeek( psSHP->fpSHP, nRecordOffset, 0 ) != 0 )
     {
-        psSHP->sHooks.Error( "Error in psSHP->sHooks.FSeek() while writing object to .shp file." );
+        char szErrorMsg[200];
+
+        snprintf( szErrorMsg, sizeof(szErrorMsg),
+                 "Error in psSHP->sHooks.FSeek() while writing object to .shp file: %s",
+                  strerror(errno) );
+        szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+        psSHP->sHooks.Error( szErrorMsg );
+
         free( pabyRec );
         return -1;
     }
     if( psSHP->sHooks.FWrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )
     {
-        psSHP->sHooks.Error( "Error in psSHP->sHooks.Fwrite() while writing object to .shp file." );
+        char szErrorMsg[200];
+
+        snprintf( szErrorMsg, sizeof(szErrorMsg),
+                 "Error in psSHP->sHooks.FWrite() while writing object of %u bytes to .shp file: %s",
+                  nRecordSize, strerror(errno) );
+        szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+        psSHP->sHooks.Error( szErrorMsg );
+
         free( pabyRec );
         return -1;
     }
-    
+
     free( pabyRec );
 
+    if( bAppendToLastRecord )
+    {
+        psSHP->nFileSize = psSHP->panRecOffset[nShapeId] + nRecordSize; 
+    }
+    else if( bAppendToFile )
+    {
+        if( nShapeId == -1 )
+            nShapeId = psSHP->nRecords++;
+
+        psSHP->panRecOffset[nShapeId] = psSHP->nFileSize;
+        psSHP->nFileSize += nRecordSize;
+    }
+    psSHP->panRecSize[nShapeId] = nRecordSize-8;
+
 /* -------------------------------------------------------------------- */
 /*     Expand file wide bounds based on this shape.                    */
 /* -------------------------------------------------------------------- */
@@ -1546,8 +1997,8 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
         {
             psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0];
             psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0];
-            psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ[0];
-            psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM[0];
+            psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ ? psObject->padfZ[0] : 0.0;
+            psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM ? psObject->padfM[0] : 0.0;
         }
     }
 
@@ -1555,17 +2006,68 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
     {
         psSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0],psObject->padfX[i]);
         psSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1],psObject->padfY[i]);
-        psSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]);
-        psSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]);
         psSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0],psObject->padfX[i]);
         psSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1],psObject->padfY[i]);
-        psSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]);
-        psSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]);
+        if( psObject->padfZ )
+        {
+            psSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]);
+            psSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]);
+        }
+        if( psObject->padfM )
+        {
+            psSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]);
+            psSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]);
+        }
     }
 
     return( nShapeId  );
 }
 
+/************************************************************************/
+/*                         SHPAllocBuffer()                             */
+/************************************************************************/
+
+static void* SHPAllocBuffer(unsigned char** pBuffer, int nSize)
+{
+    unsigned char* pRet;
+
+    if( pBuffer == NULL )
+        return calloc(1, nSize);
+
+    pRet = *pBuffer;
+    if( pRet == NULL )
+        return NULL;
+
+    (*pBuffer) += nSize;
+    return pRet;
+}
+
+/************************************************************************/
+/*                    SHPReallocObjectBufIfNecessary()                  */
+/************************************************************************/
+
+static unsigned char* SHPReallocObjectBufIfNecessary ( SHPHandle psSHP,
+                                                       int nObjectBufSize )
+{
+    unsigned char* pBuffer;
+    if( nObjectBufSize == 0 )
+    {
+        nObjectBufSize = 4 * sizeof(double);
+    }
+    if( nObjectBufSize > psSHP->nObjectBufSize )
+    {
+        pBuffer = (unsigned char*) realloc( psSHP->pabyObjectBuf, nObjectBufSize );
+        if( pBuffer != NULL )
+        {
+            psSHP->pabyObjectBuf = pBuffer;
+            psSHP->nObjectBufSize = nObjectBufSize;
+        }
+    }
+    else
+        pBuffer = psSHP->pabyObjectBuf;
+    return pBuffer;
+}
+
 /************************************************************************/
 /*                          SHPReadObject()                             */
 /*                                                                      */
@@ -1580,6 +2082,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
     int                  nEntitySize, nRequiredSize;
     SHPObject           *psShape;
     char                 szErrorMsg[128];
+    int                  nSHPType;
+    int                  nBytesRead;
 
 /* -------------------------------------------------------------------- */
 /*      Validate the record/entity number.                              */
@@ -1587,29 +2091,113 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
     if( hEntity < 0 || hEntity >= psSHP->nRecords )
         return( NULL );
 
+/* -------------------------------------------------------------------- */
+/*      Read offset/length from SHX loading if necessary.               */
+/* -------------------------------------------------------------------- */
+    if( psSHP->panRecOffset[hEntity] == 0 && psSHP->fpSHX != NULL )
+    {
+        unsigned int       nOffset, nLength;
+
+        if( psSHP->sHooks.FSeek( psSHP->fpSHX, 100 + 8 * hEntity, 0 ) != 0 ||
+            psSHP->sHooks.FRead( &nOffset, 1, 4, psSHP->fpSHX ) != 4 ||
+            psSHP->sHooks.FRead( &nLength, 1, 4, psSHP->fpSHX ) != 4 )
+        {
+            char str[128];
+            snprintf( str, sizeof(str),
+                    "Error in fseek()/fread() reading object from .shx file at offset %d",
+                    100 + 8 * hEntity);
+            str[sizeof(str)-1] = '\0';
+
+            psSHP->sHooks.Error( str );
+            return NULL;
+        }
+        if( !bBigEndian ) SwapWord( 4, &nOffset );
+        if( !bBigEndian ) SwapWord( 4, &nLength );
+
+        if( nOffset > (unsigned int)INT_MAX )
+        {
+            char str[128];
+            snprintf( str, sizeof(str),
+                    "Invalid offset for entity %d", hEntity);
+            str[sizeof(str)-1] = '\0';
+
+            psSHP->sHooks.Error( str );
+            return NULL;
+        }
+        if( nLength > (unsigned int)(INT_MAX / 2 - 4) )
+        {
+            char str[128];
+            snprintf( str, sizeof(str),
+                    "Invalid length for entity %d", hEntity);
+            str[sizeof(str)-1] = '\0';
+
+            psSHP->sHooks.Error( str );
+            return NULL;
+        }
+
+        psSHP->panRecOffset[hEntity] = nOffset*2;
+        psSHP->panRecSize[hEntity] = nLength*2;
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Ensure our record buffer is large enough.                       */
 /* -------------------------------------------------------------------- */
     nEntitySize = psSHP->panRecSize[hEntity]+8;
     if( nEntitySize > psSHP->nBufSize )
     {
-        psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,nEntitySize);
-        if (psSHP->pabyRec == NULL)
+        uchar* pabyRecNew;
+        int nNewBufSize = nEntitySize;
+        if( nNewBufSize < INT_MAX - nNewBufSize / 3 )
+            nNewBufSize += nNewBufSize / 3;
+        else
+            nNewBufSize = INT_MAX;
+
+        /* Before allocating too much memory, check that the file is big enough */
+        /* and do not trust the file size in the header the first time we */
+        /* need to allocate more than 10 MB */
+        if( nNewBufSize >= 10 * 1024 * 1024 &&
+            psSHP->nBufSize < 10 * 1024 * 1024 )
         {
-            char szError[200];
+            SAOffset nFileSize;
+            psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 2 );
+            nFileSize = psSHP->sHooks.FTell(psSHP->fpSHP);
+            if( nFileSize >= UINT_MAX )
+                psSHP->nFileSize = UINT_MAX;
+            else
+                psSHP->nFileSize = (unsigned int)nFileSize;
+        }
 
-            /* Reallocate previous successfull size for following features */
-            psSHP->pabyRec = (uchar *) malloc(psSHP->nBufSize);
+        if( psSHP->panRecOffset[hEntity] >= psSHP->nFileSize ||
+            /* We should normally use nEntitySize instead of*/
+            /* psSHP->panRecSize[hEntity] in the below test, but because of */
+            /* the case of non conformant .shx files detailed a bit below, */
+            /* let be more tolerant */
+            psSHP->panRecSize[hEntity] > psSHP->nFileSize - psSHP->panRecOffset[hEntity] )
+        {
+            char str[128];
+            snprintf( str, sizeof(str),
+                        "Error in fread() reading object of size %d at offset %u from .shp file",
+                        nEntitySize, psSHP->panRecOffset[hEntity] );
+            str[sizeof(str)-1] = '\0';
 
-            sprintf( szError, 
-                     "Not enough memory to allocate requested memory (nBufSize=%d). "
-                     "Probably broken SHP file", psSHP->nBufSize );
-            psSHP->sHooks.Error( szError );
+            psSHP->sHooks.Error( str );
             return NULL;
         }
 
-        /* Only set new buffer size after successfull alloc */
-        psSHP->nBufSize = nEntitySize;
+        pabyRecNew = (uchar *) SfRealloc(psSHP->pabyRec,nNewBufSize);
+        if (pabyRecNew == NULL)
+        {
+            snprintf( szErrorMsg, sizeof(szErrorMsg),
+                     "Not enough memory to allocate requested memory (nNewBufSize=%d). "
+                     "Probably broken SHP file", nNewBufSize);
+            szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+            psSHP->sHooks.Error( szErrorMsg );
+            return NULL;
+        }
+
+        /* Only set new buffer size after successful alloc */
+        psSHP->pabyRec = pabyRecNew;
+        psSHP->nBufSize = nNewBufSize;
     }
 
     /* In case we were not able to reallocate the buffer on a previous step */
@@ -1628,48 +2216,93 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
          * for example to detect if file is truncated.
          */
         char str[128];
-        sprintf( str,
+        snprintf( str, sizeof(str),
                  "Error in fseek() reading object from .shp file at offset %u",
                  psSHP->panRecOffset[hEntity]);
+        str[sizeof(str)-1] = '\0';
 
         psSHP->sHooks.Error( str );
         return NULL;
     }
 
-    if( psSHP->sHooks.FRead( psSHP->pabyRec, nEntitySize, 1, psSHP->fpSHP ) != 1 )
+    nBytesRead = (int)psSHP->sHooks.FRead( psSHP->pabyRec, 1, nEntitySize, psSHP->fpSHP );
+
+    /* Special case for a shapefile whose .shx content length field is not equal */
+    /* to the content length field of the .shp, which is a violation of "The */
+    /* content length stored in the index record is the same as the value stored in the main */
+    /* file record header." (http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf, page 24) */
+    /* Actually in that case the .shx content length is equal to the .shp content length + */
+    /* 4 (16 bit words), representing the 8 bytes of the record header... */
+    if( nBytesRead >= 8 && nBytesRead == nEntitySize - 8 )
+    {
+        /* Do a sanity check */
+        int nSHPContentLength;
+        memcpy( &nSHPContentLength, psSHP->pabyRec + 4, 4 );
+        if( !bBigEndian ) SwapWord( 4, &(nSHPContentLength) );
+        if( nSHPContentLength < 0 ||
+            nSHPContentLength > INT_MAX / 2 - 4 ||
+            2 * nSHPContentLength + 8 != nBytesRead )
+        {
+            char str[128];
+            snprintf( str, sizeof(str),
+                    "Sanity check failed when trying to recover from inconsistent .shx/.shp with shape %d",
+                    hEntity );
+            str[sizeof(str)-1] = '\0';
+
+            psSHP->sHooks.Error( str );
+            return NULL;
+        }
+    }
+    else if( nBytesRead != nEntitySize )
     {
         /*
          * TODO - mloskot: Consider detailed diagnostics of shape file,
          * for example to detect if file is truncated.
          */
         char str[128];
-        sprintf( str,
-                 "Error in fread() reading object of size %u at offset %u from .shp file",
+        snprintf( str, sizeof(str),
+                 "Error in fread() reading object of size %d at offset %u from .shp file",
                  nEntitySize, psSHP->panRecOffset[hEntity] );
+        str[sizeof(str)-1] = '\0';
 
         psSHP->sHooks.Error( str );
         return NULL;
     }
 
-/* -------------------------------------------------------------------- */
-/*     Allocate and minimally initialize the object.                   */
-/* -------------------------------------------------------------------- */
-    psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
-    psShape->nShapeId = hEntity;
-    psShape->bMeasureIsUsed = FALSE;
-
     if ( 8 + 4 > nEntitySize )
     {
         snprintf(szErrorMsg, sizeof(szErrorMsg),
                  "Corrupted .shp file : shape %d : nEntitySize = %d",
-                 hEntity, nEntitySize); 
+                 hEntity, nEntitySize);
+        szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
         psSHP->sHooks.Error( szErrorMsg );
-        SHPDestroyObject(psShape);
         return NULL;
     }
-    memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 );
+    memcpy( &nSHPType, psSHP->pabyRec + 8, 4 );
 
-    if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) );
+    if( bBigEndian ) SwapWord( 4, &(nSHPType) );
+
+/* -------------------------------------------------------------------- */
+/*     Allocate and minimally initialize the object.                   */
+/* -------------------------------------------------------------------- */
+    if( psSHP->bFastModeReadObject )
+    {
+        if( psSHP->psCachedObject->bFastModeReadObject )
+        {
+            psSHP->sHooks.Error( "Invalid read pattern in fast read mode. "
+                                 "SHPDestroyObject() should be called." );
+            return NULL;
+        }
+
+        psShape = psSHP->psCachedObject;
+        memset(psShape, 0, sizeof(SHPObject));
+    }
+    else
+        psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
+    psShape->nShapeId = hEntity;
+    psShape->nSHPType = nSHPType;
+    psShape->bMeasureIsUsed = FALSE;
+    psShape->bFastModeReadObject = psSHP->bFastModeReadObject;
 
 /* ==================================================================== */
 /*  Extract vertices for a Polygon or Arc.                             */
@@ -1681,14 +2314,17 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         || psShape->nSHPType == SHPT_ARCM
         || psShape->nSHPType == SHPT_MULTIPATCH )
     {
-        int32_t                nPoints, nParts;
+        int32          nPoints, nParts;
         int                    i, nOffset;
+        unsigned char* pBuffer = NULL;
+        unsigned char** ppBuffer = NULL;
 
         if ( 40 + 8 + 4 > nEntitySize )
         {
             snprintf(szErrorMsg, sizeof(szErrorMsg),
                      "Corrupted .shp file : shape %d : nEntitySize = %d",
-                     hEntity, nEntitySize); 
+                     hEntity, nEntitySize);
+            szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
             psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
@@ -1716,17 +2352,19 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         if( bBigEndian ) SwapWord( 4, &nPoints );
         if( bBigEndian ) SwapWord( 4, &nParts );
 
-        if (nPoints < 0 || nParts < 0 ||
+        /* nPoints and nParts are unsigned */
+        if (/* nPoints < 0 || nParts < 0 || */
             nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000)
         {
             snprintf(szErrorMsg, sizeof(szErrorMsg),
-                     "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d.",
+                     "Corrupted .shp file : shape %d, nPoints=%u, nParts=%u.",
                      hEntity, nPoints, nParts);
+            szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
             psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
-        
+
         /* With the previous checks on nPoints and nParts, */
         /* we should not overflow here and after */
         /* since 50 M * (16 + 8 + 8) = 1 600 MB */
@@ -1744,23 +2382,31 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         if (nRequiredSize > nEntitySize)
         {
             snprintf(szErrorMsg, sizeof(szErrorMsg),
-                     "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d, nEntitySize=%d.",
+                     "Corrupted .shp file : shape %d, nPoints=%u, nParts=%u, nEntitySize=%d.",
                      hEntity, nPoints, nParts, nEntitySize);
+            szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
             psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
 
+        if( psShape->bFastModeReadObject )
+        {
+            int nObjectBufSize = 4 * sizeof(double) * nPoints + 2 * sizeof(int) * nParts;
+            pBuffer = SHPReallocObjectBufIfNecessary(psSHP, nObjectBufSize);
+            ppBuffer = &pBuffer;
+        }
+
         psShape->nVertices = nPoints;
-        psShape->padfX = (double *) calloc(nPoints,sizeof(double));
-        psShape->padfY = (double *) calloc(nPoints,sizeof(double));
-        psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
-        psShape->padfM = (double *) calloc(nPoints,sizeof(double));
+        psShape->padfX = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+        psShape->padfY = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+        psShape->padfZ = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+        psShape->padfM = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
 
         psShape->nParts = nParts;
-        psShape->panPartStart = (int *) calloc(nParts,sizeof(int));
-        psShape->panPartType = (int *) calloc(nParts,sizeof(int));
-        
+        psShape->panPartStart = (int *) SHPAllocBuffer(ppBuffer, nParts * sizeof(int));
+        psShape->panPartType = (int *) SHPAllocBuffer(ppBuffer, nParts * sizeof(int));
+
         if (psShape->padfX == NULL ||
             psShape->padfY == NULL ||
             psShape->padfZ == NULL ||
@@ -1769,32 +2415,35 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
             psShape->panPartType == NULL)
         {
             snprintf(szErrorMsg, sizeof(szErrorMsg),
-                     "Not enough memory to allocate requested memory (nPoints=%d, nParts=%d) for shape %d. "
-                     "Probably broken SHP file", hEntity, nPoints, nParts );
+                    "Not enough memory to allocate requested memory (nPoints=%u, nParts=%u) for shape %d. "
+                    "Probably broken SHP file", nPoints, nParts, hEntity );
+            szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
             psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
 
-        for( i = 0; i < nParts; i++ )
+        for( i = 0; (int32)i < nParts; i++ )
             psShape->panPartType[i] = SHPP_RING;
 
 /* -------------------------------------------------------------------- */
 /*      Copy out the part array from the record.                        */
 /* -------------------------------------------------------------------- */
         memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts );
-        for( i = 0; i < nParts; i++ )
+        for( i = 0; (int32)i < nParts; i++ )
         {
             if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i );
 
             /* We check that the offset is inside the vertex array */
             if (psShape->panPartStart[i] < 0
                 || (psShape->panPartStart[i] >= psShape->nVertices
-                    && psShape->nVertices > 0) )
+                    && psShape->nVertices > 0)
+                || (psShape->panPartStart[i] > 0 && psShape->nVertices == 0) )
             {
                 snprintf(szErrorMsg, sizeof(szErrorMsg),
                          "Corrupted .shp file : shape %d : panPartStart[%d] = %d, nVertices = %d",
-                         hEntity, i, psShape->panPartStart[i], psShape->nVertices); 
+                         hEntity, i, psShape->panPartStart[i], psShape->nVertices);
+                szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
                 psSHP->sHooks.Error( szErrorMsg );
                 SHPDestroyObject(psShape);
                 return NULL;
@@ -1803,7 +2452,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
             {
                 snprintf(szErrorMsg, sizeof(szErrorMsg),
                          "Corrupted .shp file : shape %d : panPartStart[%d] = %d, panPartStart[%d] = %d",
-                         hEntity, i, psShape->panPartStart[i], i - 1, psShape->panPartStart[i - 1]); 
+                         hEntity, i, psShape->panPartStart[i], i - 1, psShape->panPartStart[i - 1]);
+                szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
                 psSHP->sHooks.Error( szErrorMsg );
                 SHPDestroyObject(psShape);
                 return NULL;
@@ -1818,18 +2468,18 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         if( psShape->nSHPType == SHPT_MULTIPATCH )
         {
             memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts );
-            for( i = 0; i < nParts; i++ )
+            for( i = 0; (int32)i < nParts; i++ )
             {
                 if( bBigEndian ) SwapWord( 4, psShape->panPartType+i );
             }
 
             nOffset += 4*nParts;
         }
-        
+
 /* -------------------------------------------------------------------- */
 /*      Copy out the vertices from the record.                          */
 /* -------------------------------------------------------------------- */
-        for( i = 0; i < nPoints; i++ )
+        for( i = 0; (int32)i < nPoints; i++ )
         {
             memcpy(psShape->padfX + i,
                    psSHP->pabyRec + nOffset + i * 16,
@@ -1844,7 +2494,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         }
 
         nOffset += 16*nPoints;
-        
+
 /* -------------------------------------------------------------------- */
 /*      If we have a Z coordinate, collect that now.                    */
 /* -------------------------------------------------------------------- */
@@ -1854,11 +2504,11 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         {
             memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
             memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
-            
+
             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
-            
-            for( i = 0; i < nPoints; i++ )
+
+            for( i = 0; (int32)i < nPoints; i++ )
             {
                 memcpy( psShape->padfZ + i,
                         psSHP->pabyRec + nOffset + 16 + i*8, 8 );
@@ -1867,6 +2517,10 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 
             nOffset += 16 + 8*nPoints;
         }
+        else if( psShape->bFastModeReadObject )
+        {
+            psShape->padfZ = NULL;
+        }
 
 /* -------------------------------------------------------------------- */
 /*      If we have a M measure value, then read it now.  We assume      */
@@ -1874,15 +2528,15 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 /*      big enough, but really it will only occur for the Z shapes      */
 /*      (options), and the M shapes.                                    */
 /* -------------------------------------------------------------------- */
-        if( nEntitySize >= nOffset + 16 + 8*nPoints )
+        if( nEntitySize >= (int)(nOffset + 16 + 8*nPoints) )
         {
             memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
             memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
-            
+
             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
-            
-            for( i = 0; i < nPoints; i++ )
+
+            for( i = 0; (int32)i < nPoints; i++ )
             {
                 memcpy( psShape->padfM + i,
                         psSHP->pabyRec + nOffset + 16 + i*8, 8 );
@@ -1890,6 +2544,10 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
             }
             psShape->bMeasureIsUsed = TRUE;
         }
+        else if( psShape->bFastModeReadObject )
+        {
+            psShape->padfM = NULL;
+        }
     }
 
 /* ==================================================================== */
@@ -1899,14 +2557,17 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
              || psShape->nSHPType == SHPT_MULTIPOINTM
              || psShape->nSHPType == SHPT_MULTIPOINTZ )
     {
-        int32_t                nPoints;
+        int32          nPoints;
         int                    i, nOffset;
+        unsigned char* pBuffer = NULL;
+        unsigned char** ppBuffer = NULL;
 
         if ( 44 + 4 > nEntitySize )
         {
             snprintf(szErrorMsg, sizeof(szErrorMsg),
                      "Corrupted .shp file : shape %d : nEntitySize = %d",
-                     hEntity, nEntitySize); 
+                     hEntity, nEntitySize);
+            szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
             psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
@@ -1915,11 +2576,13 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 
         if( bBigEndian ) SwapWord( 4, &nPoints );
 
-        if (nPoints < 0 || nPoints > 50 * 1000 * 1000)
+        /* nPoints is unsigned */
+        if (/* nPoints < 0 || */ nPoints > 50 * 1000 * 1000)
         {
             snprintf(szErrorMsg, sizeof(szErrorMsg),
-                     "Corrupted .shp file : shape %d : nPoints = %d",
-                     hEntity, nPoints); 
+                     "Corrupted .shp file : shape %d : nPoints = %u",
+                     hEntity, nPoints);
+            szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
             psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
@@ -1933,18 +2596,27 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         if (nRequiredSize > nEntitySize)
         {
             snprintf(szErrorMsg, sizeof(szErrorMsg),
-                     "Corrupted .shp file : shape %d : nPoints = %d, nEntitySize = %d",
-                     hEntity, nPoints, nEntitySize); 
+                     "Corrupted .shp file : shape %d : nPoints = %u, nEntitySize = %d",
+                     hEntity, nPoints, nEntitySize);
+            szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
             psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
-        
+
+        if( psShape->bFastModeReadObject )
+        {
+            int nObjectBufSize = 4 * sizeof(double) * nPoints;
+            pBuffer = SHPReallocObjectBufIfNecessary(psSHP, nObjectBufSize);
+            ppBuffer = &pBuffer;
+        }
+
         psShape->nVertices = nPoints;
-        psShape->padfX = (double *) calloc(nPoints,sizeof(double));
-        psShape->padfY = (double *) calloc(nPoints,sizeof(double));
-        psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
-        psShape->padfM = (double *) calloc(nPoints,sizeof(double));
+
+        psShape->padfX = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+        psShape->padfY = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+        psShape->padfZ = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+        psShape->padfM = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
 
         if (psShape->padfX == NULL ||
             psShape->padfY == NULL ||
@@ -1952,14 +2624,15 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
             psShape->padfM == NULL)
         {
             snprintf(szErrorMsg, sizeof(szErrorMsg),
-                     "Not enough memory to allocate requested memory (nPoints=%d) for shape %d. "
-                     "Probably broken SHP file", hEntity, nPoints );
+                     "Not enough memory to allocate requested memory (nPoints=%u) for shape %d. "
+                     "Probably broken SHP file", nPoints, hEntity );
+            szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
             psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
         }
 
-        for( i = 0; i < nPoints; i++ )
+        for( i = 0; (int32)i < nPoints; i++ )
         {
             memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 );
             memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 );
@@ -1969,7 +2642,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         }
 
         nOffset = 48 + 16*nPoints;
-        
+
 /* -------------------------------------------------------------------- */
 /*     Get the X/Y bounds.                                             */
 /* -------------------------------------------------------------------- */
@@ -1990,11 +2663,11 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         {
             memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
             memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
-            
+
             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
-            
-            for( i = 0; i < nPoints; i++ )
+
+            for( i = 0; (int32)i < nPoints; i++ )
             {
                 memcpy( psShape->padfZ + i,
                         psSHP->pabyRec + nOffset + 16 + i*8, 8 );
@@ -2003,6 +2676,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 
             nOffset += 16 + 8*nPoints;
         }
+        else if( psShape->bFastModeReadObject )
+            psShape->padfZ = NULL;
 
 /* -------------------------------------------------------------------- */
 /*      If we have a M measure value, then read it now.  We assume      */
@@ -2010,15 +2685,15 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 /*      big enough, but really it will only occur for the Z shapes      */
 /*      (options), and the M shapes.                                    */
 /* -------------------------------------------------------------------- */
-        if( nEntitySize >= nOffset + 16 + 8*nPoints )
+        if( nEntitySize >= (int)(nOffset + 16 + 8*nPoints) )
         {
             memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
             memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
-            
+
             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
-            
-            for( i = 0; i < nPoints; i++ )
+
+            for( i = 0; (int32)i < nPoints; i++ )
             {
                 memcpy( psShape->padfM + i,
                         psSHP->pabyRec + nOffset + 16 + i*8, 8 );
@@ -2026,6 +2701,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
             }
             psShape->bMeasureIsUsed = TRUE;
         }
+        else if( psShape->bFastModeReadObject )
+            psShape->padfM = NULL;
     }
 
 /* ==================================================================== */
@@ -2036,18 +2713,31 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
              || psShape->nSHPType == SHPT_POINTZ )
     {
         int    nOffset;
-        
+
         psShape->nVertices = 1;
-        psShape->padfX = (double *) calloc(1,sizeof(double));
-        psShape->padfY = (double *) calloc(1,sizeof(double));
-        psShape->padfZ = (double *) calloc(1,sizeof(double));
-        psShape->padfM = (double *) calloc(1,sizeof(double));
+        if( psShape->bFastModeReadObject )
+        {
+            psShape->padfX = &(psShape->dfXMin);
+            psShape->padfY = &(psShape->dfYMin);
+            psShape->padfZ = &(psShape->dfZMin);
+            psShape->padfM = &(psShape->dfMMin);
+            psShape->padfZ[0] = 0.0;
+            psShape->padfM[0] = 0.0;
+        }
+        else
+        {
+            psShape->padfX = (double *) calloc(1,sizeof(double));
+            psShape->padfY = (double *) calloc(1,sizeof(double));
+            psShape->padfZ = (double *) calloc(1,sizeof(double));
+            psShape->padfM = (double *) calloc(1,sizeof(double));
+        }
 
         if (20 + 8 + (( psShape->nSHPType == SHPT_POINTZ ) ? 8 : 0)> nEntitySize)
         {
             snprintf(szErrorMsg, sizeof(szErrorMsg),
                      "Corrupted .shp file : shape %d : nEntitySize = %d",
-                     hEntity, nEntitySize); 
+                     hEntity, nEntitySize);
+            szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
             psSHP->sHooks.Error( szErrorMsg );
             SHPDestroyObject(psShape);
             return NULL;
@@ -2059,16 +2749,16 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         if( bBigEndian ) SwapWord( 8, psShape->padfY );
 
         nOffset = 20 + 8;
-        
+
 /* -------------------------------------------------------------------- */
 /*      If we have a Z coordinate, collect that now.                    */
 /* -------------------------------------------------------------------- */
         if( psShape->nSHPType == SHPT_POINTZ )
         {
             memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 );
-        
+
             if( bBigEndian ) SwapWord( 8, psShape->padfZ );
-            
+
             nOffset += 8;
         }
 
@@ -2081,7 +2771,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         if( nEntitySize >= nOffset + 8 )
         {
             memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 );
-        
+
             if( bBigEndian ) SwapWord( 8, psShape->padfM );
             psShape->bMeasureIsUsed = TRUE;
         }
@@ -2123,7 +2813,7 @@ SHPTypeName( int nSHPType )
 
       case SHPT_MULTIPOINT:
         return "MultiPoint";
-        
+
       case SHPT_POINTZ:
         return "PointZ";
 
@@ -2135,7 +2825,7 @@ SHPTypeName( int nSHPType )
 
       case SHPT_MULTIPOINTZ:
         return "MultiPointZ";
-        
+
       case SHPT_POINTM:
         return "PointM";
 
@@ -2168,7 +2858,7 @@ SHPPartTypeName( int nPartType )
     {
       case SHPP_TRISTRIP:
         return "TriangleStrip";
-        
+
       case SHPP_TRIFAN:
         return "TriangleFan";
 
@@ -2199,7 +2889,13 @@ SHPDestroyObject( SHPObject * psShape )
 {
     if( psShape == NULL )
         return;
-    
+
+    if( psShape->bFastModeReadObject )
+    {
+        psShape->bFastModeReadObject = FALSE;
+        return;
+    }
+
     if( psShape->padfX != NULL )
         free( psShape->padfX );
     if( psShape->padfY != NULL )
@@ -2225,8 +2921,8 @@ SHPDestroyObject( SHPObject * psShape )
 /************************************************************************/
 
 int SHPAPI_CALL
-SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
-
+SHPRewindObject( CPL_UNUSED SHPHandle hSHP,
+                 SHPObject * psObject )
 {
     int  iOpRing, bAltered = 0;
 
@@ -2273,14 +2969,14 @@ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
 
             if( iCheckRing == iOpRing )
                 continue;
-            
+
             nVertStart = psObject->panPartStart[iCheckRing];
 
             if( iCheckRing == psObject->nParts-1 )
-                nVertCount = psObject->nVertices 
+                nVertCount = psObject->nVertices
                     - psObject->panPartStart[iCheckRing];
             else
-                nVertCount = psObject->panPartStart[iCheckRing+1] 
+                nVertCount = psObject->panPartStart[iCheckRing+1]
                     - psObject->panPartStart[iCheckRing];
 
             for( iEdge = 0; iEdge < nVertCount; iEdge++ )
@@ -2294,7 +2990,7 @@ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
 
                 /* Rule #1:
                  * Test whether the edge 'straddles' the horizontal ray from the test point (dfTestY,dfTestY)
-                 * The rule #1 also excludes edges collinear with the ray.
+                 * The rule #1 also excludes edges colinear with the ray.
                  */
                 if ( ( psObject->padfY[iEdge+nVertStart] < dfTestY
                        && dfTestY <= psObject->padfY[iNext+nVertStart] )
@@ -2304,9 +3000,9 @@ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
                     /* Rule #2:
                      * Test if edge-ray intersection is on the right from the test point (dfTestY,dfTestY)
                      */
-                    double const intersect = 
+                    double const intersect =
                         ( psObject->padfX[iEdge+nVertStart]
-                          + ( dfTestY - psObject->padfY[iEdge+nVertStart] ) 
+                          + ( dfTestY - psObject->padfY[iEdge+nVertStart] )
                           / ( psObject->padfY[iNext+nVertStart] - psObject->padfY[iEdge+nVertStart] )
                           * ( psObject->padfX[iNext+nVertStart] - psObject->padfX[iEdge+nVertStart] ) );
 
@@ -2314,7 +3010,7 @@ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
                     {
                         bInner = !bInner;
                     }
-                }    
+                }
             }
         } /* for iCheckRing */
 
@@ -2327,7 +3023,7 @@ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
         if( iOpRing == psObject->nParts-1 )
             nVertCount = psObject->nVertices - psObject->panPartStart[iOpRing];
         else
-            nVertCount = psObject->panPartStart[iOpRing+1] 
+            nVertCount = psObject->panPartStart[iOpRing+1]
                 - psObject->panPartStart[iOpRing];
 
         if (nVertCount < 2)
@@ -2355,13 +3051,13 @@ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
 
                 /* Swap X */
                 dfSaved = psObject->padfX[nVertStart+i];
-                psObject->padfX[nVertStart+i] = 
+                psObject->padfX[nVertStart+i] =
                     psObject->padfX[nVertStart+nVertCount-i-1];
                 psObject->padfX[nVertStart+nVertCount-i-1] = dfSaved;
 
                 /* Swap Y */
                 dfSaved = psObject->padfY[nVertStart+i];
-                psObject->padfY[nVertStart+i] = 
+                psObject->padfY[nVertStart+i] =
                     psObject->padfY[nVertStart+nVertCount-i-1];
                 psObject->padfY[nVertStart+nVertCount-i-1] = dfSaved;
 
@@ -2369,7 +3065,7 @@ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
                 if( psObject->padfZ )
                 {
                     dfSaved = psObject->padfZ[nVertStart+i];
-                    psObject->padfZ[nVertStart+i] = 
+                    psObject->padfZ[nVertStart+i] =
                         psObject->padfZ[nVertStart+nVertCount-i-1];
                     psObject->padfZ[nVertStart+nVertCount-i-1] = dfSaved;
                 }
@@ -2378,7 +3074,7 @@ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
                 if( psObject->padfM )
                 {
                     dfSaved = psObject->padfM[nVertStart+i];
-                    psObject->padfM[nVertStart+i] = 
+                    psObject->padfM[nVertStart+i] =
                         psObject->padfM[nVertStart+nVertCount-i-1];
                     psObject->padfM[nVertStart+nVertCount-i-1] = dfSaved;
                 }